├── app
├── .gitignore
├── src
│ └── main
│ │ ├── res
│ │ ├── values-b+afh
│ │ │ └── strings.xml
│ │ ├── values
│ │ │ ├── dimens.xml
│ │ │ ├── styles.xml
│ │ │ ├── colors.xml
│ │ │ ├── strings.xml
│ │ │ └── themes.xml
│ │ ├── values-land
│ │ │ └── dimens.xml
│ │ ├── font
│ │ │ ├── pixel.TTF
│ │ │ └── quicksand.ttf
│ │ ├── values-w1240dp
│ │ │ └── dimens.xml
│ │ ├── values-w600dp
│ │ │ └── dimens.xml
│ │ ├── mipmap-hdpi
│ │ │ ├── ic_launcher.png
│ │ │ ├── ic_launcher_round.png
│ │ │ └── ic_launcher_foreground.png
│ │ ├── mipmap-mdpi
│ │ │ ├── ic_launcher.png
│ │ │ ├── ic_launcher_round.png
│ │ │ └── ic_launcher_foreground.png
│ │ ├── mipmap-xhdpi
│ │ │ ├── ic_launcher.png
│ │ │ ├── ic_launcher_round.png
│ │ │ └── ic_launcher_foreground.png
│ │ ├── mipmap-xxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ ├── ic_launcher_round.png
│ │ │ └── ic_launcher_foreground.png
│ │ ├── mipmap-xxxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ ├── ic_launcher_round.png
│ │ │ └── ic_launcher_foreground.png
│ │ ├── drawable
│ │ │ ├── icon_game_od_life_dark2.png
│ │ │ ├── rect.xml
│ │ │ ├── common_round_card.xml
│ │ │ ├── common_less_round_card.xml
│ │ │ ├── input_box.xml
│ │ │ ├── round_rect_left.xml
│ │ │ ├── round_rect.xml
│ │ │ ├── out_of_boundries_drawable.xml
│ │ │ ├── check.xml
│ │ │ ├── play.xml
│ │ │ ├── chevron_left.xml
│ │ │ ├── chevron_right.xml
│ │ │ ├── ic_baseline_more_vert_24.xml
│ │ │ ├── edit_2.xml
│ │ │ ├── folder.xml
│ │ │ ├── square.xml
│ │ │ ├── star.xml
│ │ │ ├── paperclip.xml
│ │ │ ├── ic_baseline_zoom_out_map_24.xml
│ │ │ ├── ic_round_photo_size_select_small_24.xml
│ │ │ ├── x.xml
│ │ │ ├── pause.xml
│ │ │ ├── chevrons_right.xml
│ │ │ ├── rotate_ccw.xml
│ │ │ ├── rotate_cw.xml
│ │ │ ├── edit_3.xml
│ │ │ ├── github.xml
│ │ │ ├── book.xml
│ │ │ ├── ic_round_ballot_24.xml
│ │ │ ├── ic_round_tune_24.xml
│ │ │ ├── copy.xml
│ │ │ ├── size_indicator.xml
│ │ │ ├── upload.xml
│ │ │ ├── external_link.xml
│ │ │ ├── save.xml
│ │ │ ├── random_cube.xml
│ │ │ ├── globe.xml
│ │ │ ├── grid.xml
│ │ │ ├── trash_2.xml
│ │ │ ├── settings.xml
│ │ │ └── share_2.xml
│ │ ├── mipmap-anydpi-v26
│ │ │ ├── ic_launcher.xml
│ │ │ └── ic_launcher_round.xml
│ │ ├── layout
│ │ │ ├── sheet_start.xml
│ │ │ ├── sheet_blueprint_library_category.xml
│ │ │ ├── sheet_predefined_selector.xml
│ │ │ ├── item_theme_picker.xml
│ │ │ ├── context_tool.xml
│ │ │ ├── fragment_second.xml
│ │ │ ├── fragment_first.xml
│ │ │ ├── item_blueprint_info_website.xml
│ │ │ ├── item_blueprint_info_misc.xml
│ │ │ ├── sheet_save_blueprint.xml
│ │ │ ├── item_rule_selection.xml
│ │ │ ├── item_preset_category.xml
│ │ │ ├── item_rule_tweak.xml
│ │ │ ├── activity_intro.xml
│ │ │ ├── item_saved_sketch.xml
│ │ │ ├── sheet_source.xml
│ │ │ ├── item_preset_extra_info.xml
│ │ │ ├── sheet_stencil.xml
│ │ │ └── item_blueprint_selection.xml
│ │ ├── drawable-v24
│ │ │ ├── round_rect_right.xml
│ │ │ └── ic_launcher_foreground.xml
│ │ ├── menu
│ │ │ └── menu_main.xml
│ │ ├── xml
│ │ │ ├── backup_rules.xml
│ │ │ └── data_extraction_rules.xml
│ │ ├── navigation
│ │ │ ├── nav_graph.xml
│ │ │ └── nav_graph2.xml
│ │ └── values-de-rDE
│ │ │ └── strings.xml
│ │ ├── ic_launcher-playstore.png
│ │ ├── java
│ │ └── leko
│ │ │ └── valmx
│ │ │ └── thegameoflife
│ │ │ ├── views
│ │ │ ├── SelectedThemeView.kt
│ │ │ ├── ThemeView.kt
│ │ │ └── ConwaysCellStateView.kt
│ │ │ ├── utils
│ │ │ ├── PresetCategory.kt
│ │ │ ├── AssetUtils.kt
│ │ │ └── blueprints
│ │ │ │ └── Blueprint.kt
│ │ │ ├── Project.kt
│ │ │ ├── game
│ │ │ ├── animations
│ │ │ │ └── Animation.kt
│ │ │ ├── FeedBackManager.kt
│ │ │ ├── PreviewManager.kt
│ │ │ ├── tools
│ │ │ │ ├── EditTool.kt
│ │ │ │ ├── copypasta
│ │ │ │ │ ├── Sketch.kt
│ │ │ │ │ └── SketchLoadSaver.kt
│ │ │ │ ├── AutoPlayTool.kt
│ │ │ │ └── PasteTool.kt
│ │ │ ├── AnimationManager.kt
│ │ │ ├── GameView.kt
│ │ │ ├── DrawManager.kt
│ │ │ ├── GridManager.kt
│ │ │ ├── utils
│ │ │ │ └── GameRuleHelper.kt
│ │ │ └── GameColors.kt
│ │ │ ├── SettingActivity.kt
│ │ │ ├── recyclers
│ │ │ ├── ContextToolsAdapter.kt
│ │ │ ├── BlueprintCategoryAdapter.kt
│ │ │ ├── RulePresetPickerAdapter.kt
│ │ │ ├── RuleSheetAdapter.kt
│ │ │ ├── BlueprintInfoRecycler.kt
│ │ │ ├── BlueprintPresetRecycler.kt
│ │ │ ├── SketchAdapter.kt
│ │ │ └── ThemeAdapter.kt
│ │ │ ├── sheets
│ │ │ ├── BlueprintPresetSelectCategorySheet.kt
│ │ │ ├── BlueprintInfoSheet.kt
│ │ │ ├── RulePresetSelectionSheet.kt
│ │ │ ├── SourceSheet.kt
│ │ │ ├── BlueprintSaveSheet.kt
│ │ │ ├── BlueprintSheet.kt
│ │ │ ├── RulesSheet.kt
│ │ │ ├── MoreOptionsSheet.kt
│ │ │ └── BlueprintPresetSelectionSheet.kt
│ │ │ └── IntroActivity.kt
│ │ ├── assets
│ │ ├── patterns
│ │ │ ├── guns
│ │ │ │ ├── p46edgeshooter.rle
│ │ │ │ ├── period113glidergun.rle
│ │ │ │ ├── period690glidergun.rle
│ │ │ │ ├── ak94.rle
│ │ │ │ ├── period246glidergun.rle
│ │ │ │ ├── period90glidergun.rle
│ │ │ │ ├── period256glidergun.rle
│ │ │ │ ├── period504glidergun.rle
│ │ │ │ ├── period174glidergun.rle
│ │ │ │ ├── period60glidergun.rle
│ │ │ │ ├── period92glidergun.rle
│ │ │ │ ├── period117gun.rle
│ │ │ │ ├── period44mwssgun.rle
│ │ │ │ ├── vacuumgun.rle
│ │ │ │ ├── period88glidergun.rle
│ │ │ │ ├── period84glidergun.rle
│ │ │ │ ├── period108glidergun.rle
│ │ │ │ └── quetzal54.rle
│ │ │ └── preview
│ │ │ │ ├── ak94.rle
│ │ │ │ ├── barge_synth.rle
│ │ │ │ └── gliderloop.rle
│ │ └── rules
│ │ │ └── rules.txt
│ │ └── AndroidManifest.xml
├── proguard-rules.pro
└── build.gradle
├── .idea
├── .gitignore
├── codeStyles
│ ├── codeStyleConfig.xml
│ └── Project.xml
├── compiler.xml
├── vcs.xml
├── discord.xml
├── misc.xml
└── gradle.xml
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── README.md
├── .gitignore
├── settings.gradle
├── gradle.properties
└── gradlew.bat
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values-b+afh/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 | 16dp
3 |
--------------------------------------------------------------------------------
/app/src/main/res/values-land/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 | 48dp
3 |
--------------------------------------------------------------------------------
/app/src/main/res/font/pixel.TTF:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/val-pu/TheGameOfLife/HEAD/app/src/main/res/font/pixel.TTF
--------------------------------------------------------------------------------
/app/src/main/res/values-w1240dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 | 200dp
3 |
--------------------------------------------------------------------------------
/app/src/main/res/values-w600dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 | 48dp
3 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/val-pu/TheGameOfLife/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/app/src/main/res/font/quicksand.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/val-pu/TheGameOfLife/HEAD/app/src/main/res/font/quicksand.ttf
--------------------------------------------------------------------------------
/app/src/main/ic_launcher-playstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/val-pu/TheGameOfLife/HEAD/app/src/main/ic_launcher-playstore.png
--------------------------------------------------------------------------------
/app/src/main/java/leko/valmx/thegameoflife/views/SelectedThemeView.kt:
--------------------------------------------------------------------------------
1 | package leko.valmx.thegameoflife.views
2 |
3 | class SelectedThemeView {
4 | }
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/val-pu/TheGameOfLife/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/val-pu/TheGameOfLife/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/val-pu/TheGameOfLife/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/val-pu/TheGameOfLife/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/val-pu/TheGameOfLife/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/val-pu/TheGameOfLife/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/val-pu/TheGameOfLife/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/val-pu/TheGameOfLife/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/icon_game_od_life_dark2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/val-pu/TheGameOfLife/HEAD/app/src/main/res/drawable/icon_game_od_life_dark2.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/val-pu/TheGameOfLife/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/val-pu/TheGameOfLife/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/val-pu/TheGameOfLife/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/val-pu/TheGameOfLife/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/val-pu/TheGameOfLife/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/val-pu/TheGameOfLife/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/val-pu/TheGameOfLife/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/.idea/codeStyles/codeStyleConfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/java/leko/valmx/thegameoflife/utils/PresetCategory.kt:
--------------------------------------------------------------------------------
1 | package leko.valmx.thegameoflife.utils
2 |
3 | class PresetCategory(val name: Int, val description: Int, val path: String, val url: String)
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/java/leko/valmx/thegameoflife/Project.kt:
--------------------------------------------------------------------------------
1 | package leko.valmx.thegameoflife
2 |
3 | object Project {
4 | const val LOG_ID = "Conway's Game Of Life"
5 | const val PREF_ID = "CGOL_VALGAMES"
6 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/rect.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/discord.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/common_round_card.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/common_less_round_card.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # TheGameOfLife
2 |
3 | The source code of an Android App Conway's Game Of Life. The source code is currently being refactored,
4 |
5 |
6 | ### How to help?
7 | Create an github issue or a pull request. Currently, there is _no_ complex pipeline for helping.
8 |
9 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Sep 19 19:19:21 CEST 2022
2 | distributionBase=GRADLE_USER_HOME
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
4 | distributionPath=wrapper/dists
5 | zipStorePath=wrapper/dists
6 | zipStoreBase=GRADLE_USER_HOME
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/input_box.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/caches
5 | /.idea/libraries
6 | /.idea/modules.xml
7 | /.idea/workspace.xml
8 | /.idea/navEditor.xml
9 | /.idea/assetWizardSettings.xml
10 | .DS_Store
11 | /build
12 | /captures
13 | .externalNativeBuild
14 | .cxx
15 | local.properties
16 | /app/release/
17 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/sheet_start.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/round_rect_left.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/round_rect_right.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/round_rect.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/out_of_boundries_drawable.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/assets/patterns/guns/p46edgeshooter.rle:
--------------------------------------------------------------------------------
1 | #N p46edgeshooter.rle
2 | #C https://conwaylife.com/wiki/Edge_shooter
3 | #C https://www.conwaylife.com/patterns/p46edgeshooter.rle
4 | x = 42, y = 32, rule = B3/S23
5 | 2o12b2o2bo4b2o2b2o$2o12bob2o6b2ob2o$15bo6bobo$15b3o4b2o2$15b3o4b2o$15b
6 | o6bobo$2o12bob2o6b2o$2o12b2o2bo4b2o7$31b3o3b3o$30bo3bobo3bo$29bo3b2ob
7 | 2o3bo$29bob2o5b2obo$31bo7bo11$31b2o5b2o$31b2o5b2o!
8 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | gradlePluginPortal()
4 | google()
5 | mavenCentral()
6 | }
7 | }
8 | dependencyResolutionManagement {
9 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
10 | repositories {
11 | google()
12 | mavenCentral()
13 | }
14 |
15 | }
16 | rootProject.name = "TheGameOfLife"
17 | include ':app'
18 |
--------------------------------------------------------------------------------
/app/src/main/assets/patterns/guns/period113glidergun.rle:
--------------------------------------------------------------------------------
1 | #N Period-113 glider gun
2 | #O Mitchell Riley, 2022
3 | #C https://conwaylife.com/wiki/Period-113_glider_gun
4 | #C https://www.conwaylife.com/patterns/period113glidergun.rle
5 | x = 47, y = 37, rule = B3/S23
6 | 44b2o$44bo$42bobo$42b2o7$29b2o14b2o$11b2o4b2o10b2o14b2o$11b2o4b2o4$26b
7 | 3o$17b3o6bo2bo$17bo2bo5bo2bo$17bo2bo6b3o$18b3o4$28b2o4b2o$2o14b2o10b2o
8 | 4b2o$2o14b2o7$3b2o$2bobo$2bo$b2o!
--------------------------------------------------------------------------------
/app/src/main/assets/patterns/guns/period690glidergun.rle:
--------------------------------------------------------------------------------
1 | #N Period-690 glider gun
2 | #O Noam Elkies, 1996
3 | #C https://conwaylife.com/wiki/Period-690_glider_gun
4 | #C https://www.conwaylife.com/patterns/period690glidergun.rle
5 | x = 52, y = 25, rule = B3/S23
6 | 11bo$11b3o$14bo$13b2o6$13b2o3b2o$13bo5bo2$14bo3bo$15b3o$33b2o$23b2o7bo
7 | bo$2o21b2o7bo17b2o$bo30b3o13bo2bo$bobo8bo35b3o$2b2o8bobo$13bobo32b3o$
8 | 13bo2bo15b3o13bo2bo$13bobo16bo17b2o$12bobo17bobo$12bo20b2o!
--------------------------------------------------------------------------------
/app/src/main/java/leko/valmx/thegameoflife/game/animations/Animation.kt:
--------------------------------------------------------------------------------
1 | package leko.valmx.thegameoflife.game.animations
2 |
3 | abstract class Animation {
4 |
5 | var animLength = 1000L
6 |
7 | var counter = 0L
8 |
9 | abstract fun onAnimate(animatedValue: Float)
10 |
11 | open fun onAnimationFinished() { }
12 |
13 | fun endAnimation() {
14 | counter = animLength * 2
15 | }
16 |
17 | abstract fun onAnimationStart()
18 |
19 | }
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_main.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/src/main/assets/patterns/guns/ak94.rle:
--------------------------------------------------------------------------------
1 | #N AK-94
2 | #O Mike Playle
3 | #C The smallest known true p94 gun, found in May 2013.
4 | #C www.conwaylife.com/wiki/AK-94
5 | x = 38, y = 25, rule = B3/S23
6 | 7bo7bo7b2o$7b3o5b3o5b2o$10bo7bo$9b2o6b2o16b2o$30b2o2bo2bo$30bobo2b2o$
7 | 33b2o$5bo28bo$5b3o26bob2o$8bo22b2obo2bo$7b2o22b2ob2o3$17bo$2b2ob2o9bob
8 | o10b2o$o2bob2o8bo3bo9bo$2obo11bo3bo10b3o$3bo11bo3bo12bo$3b2o11bobo$b2o
9 | 2bobo9bo$o2bo2b2o$b2o16b2o$19bo$13b2o5b3o$13b2o7bo!
10 |
--------------------------------------------------------------------------------
/app/src/main/assets/patterns/preview/ak94.rle:
--------------------------------------------------------------------------------
1 | #N AK-94
2 | #O Mike Playle
3 | #C The smallest known true p94 gun, found in May 2013.
4 | #C www.conwaylife.com/wiki/AK-94
5 | x = 38, y = 25, rule = B3/S23
6 | 7bo7bo7b2o$7b3o5b3o5b2o$10bo7bo$9b2o6b2o16b2o$30b2o2bo2bo$30bobo2b2o$
7 | 33b2o$5bo28bo$5b3o26bob2o$8bo22b2obo2bo$7b2o22b2ob2o3$17bo$2b2ob2o9bob
8 | o10b2o$o2bob2o8bo3bo9bo$2obo11bo3bo10b3o$3bo11bo3bo12bo$3b2o11bobo$b2o
9 | 2bobo9bo$o2bo2b2o$b2o16b2o$19bo$13b2o5b3o$13b2o7bo!
10 |
--------------------------------------------------------------------------------
/app/src/main/assets/patterns/guns/period246glidergun.rle:
--------------------------------------------------------------------------------
1 | #N Period-246 glider gun
2 | #O David Buckingham, 1996
3 | #C https://conwaylife.com/wiki/P246_gun
4 | #C https://www.conwaylife.com/patterns/period246glidergun.rle
5 | x = 43, y = 38, rule = B3/S23
6 | 34bo$34b3o$32b2o3bo$31bobob2obo$32bobobobo$36bob2o$33bo2bo$34bobo$33b
7 | 2ob2o2$2o$bo20b2o$bobo16b2o3bo$2b2o21bo15b2o$19bo5bo15bo$20bo3bo14bobo
8 | $21b3o15b2o7$29b2o$29b2o$22b2o$21bo$22b2o3$5b4o$4bo4bo$3bobo3bo$2bobo
9 | 3bo$2bo$2bo$2bo2bo$3b2o!
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/check.xml:
--------------------------------------------------------------------------------
1 |
6 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/play.xml:
--------------------------------------------------------------------------------
1 |
6 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/chevron_left.xml:
--------------------------------------------------------------------------------
1 |
6 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/chevron_right.xml:
--------------------------------------------------------------------------------
1 |
6 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_more_vert_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/assets/patterns/guns/period90glidergun.rle:
--------------------------------------------------------------------------------
1 | #N Period-90 glider gun
2 | #O Dean Hickerson
3 | #C https://conwaylife.com/wiki/Period-90_glider_gun
4 | #C https://www.conwaylife.com/patterns/period90glidergun.rle
5 | x = 64, y = 26, rule = B3/S23
6 | 39bo$39bobo$32b2o8b2o6b2o$27bo3bo2bo7b2o4bo3bo$26b8o8b2o3bo5bo$9b2o14b
7 | 2obob2o7bobo4b2obo3bo8b2o$9bo2bo11b3obo2bo7bo7bo5bo8b2o$b5o7bo11b2obob
8 | o17bo3bo$o5bo6bo12b4o20b2o$o3b2o7bo7bo5bo12bo$bo7bo2bo9bo15b2o$9b2o9b
9 | 3o16b2o3$43b2o$43b2o2$29bo$27bobo$28b2o3$40b2o$40bo$41b3o$43bo!
--------------------------------------------------------------------------------
/app/src/main/assets/patterns/guns/period256glidergun.rle:
--------------------------------------------------------------------------------
1 | #N Period 256 glider gun
2 | #O David Buckingham, 1995
3 | #C https://conwaylife.com/wiki/Period-256_glider_gun
4 | #C https://www.conwaylife.com/patterns/period256glidergun.rle
5 | x = 49, y = 49, rule = B3/S23
6 | 31b2o$31b2o5b2o$38b2o3$7b2o8b2o17b2o$7b2o9bo17b2o$18bobo21b2o$19b2o21b
7 | 2o$b2o$b2o$5b2o$5b2o15bo$22bobo$22b3o$24bo$2o$2o41b2o$43bo$41bobo$41b
8 | 2o11$6b2o39b2o$6bo40b2o$7bo$6b2o$22bobo$23b2o17b2o$23bo18b2o$46b2o$46b
9 | 2o$5b2o$5b2o$11b2o27b2o$11b2o27b2o3$9b2o$9b2o5b2o$16b2o!
--------------------------------------------------------------------------------
/app/src/main/res/drawable/edit_2.xml:
--------------------------------------------------------------------------------
1 |
6 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/assets/patterns/guns/period504glidergun.rle:
--------------------------------------------------------------------------------
1 | #N Period-504 glider gun
2 | #C https://conwaylife.com/wiki/R126
3 | #C https://www.conwaylife.com/patterns/period504glidergun.rle
4 | x = 55, y = 55, rule = B3/S23
5 | 27b2o$26bobo$26b2o3$21bo$20bobo24bo$6b2o12bobo22b3o$7bo13bo22bo$7bobo
6 | 34b2o$8b2o18b2o$29bo$29bobo$30b2o7$47b2o$46bo2bo$31bo15b2o$12b2o17bobo
7 | $13bo17b3o$10b3o20bo$2o8bo41b2o$obo49bobo$b2o41bo8b2o$42b3o$41bo$41b2o
8 | $6b2o$5bo2bo$6b2o7$23b2o$23bobo$25bo$25b2o$9b2o$10bo22bo$7b3o22bobo13b
9 | o$7bo24bobo14b2o$33bo14b2o3$27b2o$26bobo$26b2o!
--------------------------------------------------------------------------------
/app/src/main/assets/patterns/guns/period174glidergun.rle:
--------------------------------------------------------------------------------
1 | #N Period-174 glider gun
2 | #C https://conwaylife.com/wiki/Hotcrystal0_reaction
3 | #C https://www.conwaylife.com/patterns/period174glidergun.rle
4 | x = 43, y = 37, rule = B3/S23
5 | 11b2o20bo$12bo18b3o3b2o$12bobo15bo8bob2o$13b2o15b2o3bo2bo2b2o$35bobo$
6 | 27b2o7bo$27b2o$36b2o$36b2o3$7b2o8b2o$7b2o10bo$16bo$17b2o3bo$6b3o13b2o$
7 | 6b2obo2b2o7bobo$8b2o2b2o$8b2o20b4o$29bo4bo$29bo3bobo$30bo3bobo$25bo10b
8 | o$24b2o10bo$24b2o7bo2bo$24bo9b2o3$5b2o$5bobo$6b3o5b2o$7b2o5b2o$5bobo$
9 | 2o2bobo4b2o$obo2bo6bo$b4o4b3o$2b2o5bo!
--------------------------------------------------------------------------------
/app/src/main/assets/patterns/guns/period60glidergun.rle:
--------------------------------------------------------------------------------
1 | #N Period-60 glider gun
2 | #O Bill Gosper
3 | #C The first true period 60 glider gun, found by Bill Gosper.
4 | #C https://conwaylife.com/wiki/Period-60_glider_gun
5 | x = 39, y = 27, rule = B3/S23
6 | 27bo$27b4o$11bo16b4o$10bobo5b2o8bo2bo5b2o$3b2o3b2o3bo14b4o5b2o$3b2o3b
7 | 2o3bo4bobob2o3b4o$8b2o3bo5b2o3bo2bo$10bobo10bo$11bo8bo2bo2$26bobo$28bo
8 | $24bo$26bo$25bo2$11b2o$11b2o4bo$2o6b2o6b5ob2o$2o5b3o5bo2b2o4bo$8b2o5b
9 | 2o8bo12bo$11b2o4bo7bo10bobo$11b2o12bo11b2o$24bo8b2o$22b2o9bobo$35bo$
10 | 35b2o!
11 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/backup_rules.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/folder.xml:
--------------------------------------------------------------------------------
1 |
6 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/square.xml:
--------------------------------------------------------------------------------
1 |
6 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/star.xml:
--------------------------------------------------------------------------------
1 |
6 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/paperclip.xml:
--------------------------------------------------------------------------------
1 |
6 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/assets/patterns/guns/period92glidergun.rle:
--------------------------------------------------------------------------------
1 | #N Period-92 glider gun
2 | #O Martin Grant, 2017
3 | #C https://conwaylife.com/wiki/Period-92_glider_gun
4 | #C https://www.conwaylife.com/patterns/period92glidergun.rle
5 | x = 46, y = 25, rule = B3/S23
6 | 4b2o14bo$5bo13bobo$5bobo11bobo$6b2o2b2o5b3ob2o20b2o$10b2o4bo26b2o$17b
7 | 3ob2o8bo$19bob2o4b2o2bo$7b2obobo13bo5bo11b2o$7b2obobo12b2o2bobo12b2o$
8 | 7b2o3bo13b2o3bo$7b2o4b2o6b2o4b3o$o6b2o5b2o5b2o$3o7b3obo12b3o$3bo5b2o3b
9 | obobo7b2o3bo$2bobo6bo2bo3bo6b2o2bobo12b2o$2b2o7bobo2bobo7bo5bo11b2o$
10 | 27b2o2bo$2b2o27bo$2bo40b2o$4bo38b2o$3b2o$8b2o$9bo21bo$6b3o23bo$6bo23b
11 | 3o!
--------------------------------------------------------------------------------
/app/src/main/assets/patterns/guns/period117gun.rle:
--------------------------------------------------------------------------------
1 | #N Period-117 glider gun
2 | #O David Raucci, 2021
3 | #C https://conwaylife.com/wiki/Period-117_glider_gun
4 | #C https://www.conwaylife.com/patterns/period117gun.rle
5 | x = 42, y = 29, rule = B3/S23
6 | 7bo7b2o10bob2o4b2obo$7b3o5b2o10b2o2bo2bo2b2o$10bo14b2o3bo4bo3b2o$9b2o
7 | 13bo3b2ob4ob2o3bo$25b3obobo2bobob3o$12bo14bobobo2bobobo$11bobo16bo4bo$
8 | 10bo3bo16b4o$10bo3bo$10bo3bo$11bobo$12bo2$5b2o$5b2o28b2o$35b2o2$29bo$
9 | 28bobo$27bo3bo$27bo3bo$7b4o16bo3bo$6bo4bo16bobo$3bobobo2bobobo14bo$b3o
10 | bobo2bobob3o$o3b2ob4ob2o3bo13b2o$b2o3bo4bo3b2o14bo$3b2o2bo2bo2b2o10b2o
11 | 5b3o$3bob2o4b2obo10b2o7bo!
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_zoom_out_map_24.xml:
--------------------------------------------------------------------------------
1 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/data_extraction_rules.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
12 |
13 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_round_photo_size_select_small_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/assets/patterns/guns/period44mwssgun.rle:
--------------------------------------------------------------------------------
1 | #N period44mwssgun
2 | #O Dietrich Leithner, 1997
3 | #C https://conwaylife.com/wiki/Period-44_MWSS_gun
4 | #C https://www.conwaylife.com/patterns/period44mwssgun.rle
5 | x = 50, y = 40, rule = B3/S23
6 | 8bo$2b2o3bo2bo2b3o4bo$2bo2b2obobobo4bobobo2b2o$17bo7bo$3bobo7b2o5b2obo
7 | $4bo18b2o3$9b2o$9b2o2$29b2o$29bo$27bobo$15bo11b2o$2o12b3o$2o11bo3bo13b
8 | 2o$13b2ob2o13bo$46bo$45bobo$45bobo$44b2ob2o$13b2ob2o30bo$2o11bo3bo26b
9 | 2obo$2o12b3o14b2o11b2obobo$15bo7b3o4bo2bo14b2o$24bo6b3o$24b2o6bo$26bo$
10 | 24bobo$9b2o13bobo$9b2o$30b2o$30bo$4bo18b2o6b3o$3bobo7b2o5b2obo9bo$17bo
11 | 7bo$2bo2b2obobobo4bobobo2b2o$2b2o3bo2bo2b3o4bo$8bo!
--------------------------------------------------------------------------------
/app/src/main/java/leko/valmx/thegameoflife/game/FeedBackManager.kt:
--------------------------------------------------------------------------------
1 | package leko.valmx.thegameoflife.game
2 |
3 | import android.os.Build
4 | import android.os.VibrationEffect
5 | import android.os.Vibrator
6 |
7 | class FeedBackManager(val gameView: GameView) {
8 |
9 | var VIBRATION_SHORT = 100
10 |
11 | fun vibrate() {
12 |
13 | val context = gameView.context
14 |
15 | val vibrator = context.getSystemService(Vibrator::class.java) as Vibrator
16 |
17 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
18 | vibrator.vibrate(VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK))
19 | }
20 |
21 | }
22 |
23 | }
--------------------------------------------------------------------------------
/app/src/main/assets/patterns/guns/vacuumgun.rle:
--------------------------------------------------------------------------------
1 | #N Vacuum gun
2 | #O Dieter Leithner
3 | #C A true period 46 double-barreled gun found on February 21, 1997.
4 | #C www.conwaylife.com/wiki/index.php?title=Vacuum_(gun)
5 | x = 49, y = 43, rule = b3/s23
6 | b2o23b2o21b$b2o23bo22b$24bobo22b$15b2o7b2o23b$2o13bobo31b$2o13bob2o30b
7 | $16b2o31b$16bo32b$44b2o3b$16bo27b2o3b$16b2o31b$2o13bob2o13bo3bo12b$2o
8 | 13bobo13bo5bo7b2o2b$15b2o14bo13b2o2b$31b2o3bo12b$b2o30b3o13b$b2o46b$
9 | 33b3o13b$31b2o3bo12b$31bo13b2o2b$31bo5bo7b2o2b$32bo3bo12b2$44b2o3b$44b
10 | 2o3b5$37b2o10b$37bobo7b2o$39bo7b2o$37b3o9b$22bobo24b$21b3o25b$21b3o25b
11 | $21bo15b3o9b$25bobo11bo9b$21b2o4bo9bobo9b$16b2o4bo3b2o9b2o10b$15bobo6b
12 | o24b$15bo33b$14b2o!
--------------------------------------------------------------------------------
/app/src/main/res/drawable/x.xml:
--------------------------------------------------------------------------------
1 |
6 |
13 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/pause.xml:
--------------------------------------------------------------------------------
1 |
6 |
13 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/chevrons_right.xml:
--------------------------------------------------------------------------------
1 |
6 |
13 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/rotate_ccw.xml:
--------------------------------------------------------------------------------
1 |
6 |
13 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/rotate_cw.xml:
--------------------------------------------------------------------------------
1 |
6 |
13 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/edit_3.xml:
--------------------------------------------------------------------------------
1 |
6 |
13 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/github.xml:
--------------------------------------------------------------------------------
1 |
6 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/assets/patterns/guns/period88glidergun.rle:
--------------------------------------------------------------------------------
1 | #N Period-88 glider gun
2 | #O Matthias Merzenich, 2009
3 | #C https://conwaylife.com/wiki/Period-88_glider_gun
4 | #C https://www.conwaylife.com/patterns/period88glidergun.rle
5 | #C By Matthias Merzenich, September 2009
6 | #C Blocker supports by Jason Summers
7 | x = 46, y = 45, rule = B3/S23
8 | 14b2o14b2o$14b2o14b2o$30b2o$31bo$13b2obo13bobo$14bobo12b2obo$15bo$14b
9 | 2o$14b2o14b2o$14b2o14b2o4$4b2o35bo$4o4b2o26b3ob2o2b2o$3ob2o2b2o11b3o
10 | 12b4o4b2o$5bo14bo2bo16b2o$20bobo$21bo2$28b2o$27bo2bo$15b2o11bobo$15bob
11 | o11b2o$15bo2bo$16b2o2$24bo$23bobo$4b2o16bo2bo14bo$2o4b4o12b3o11b2o2b2o
12 | b3o$2o2b2ob3o26b2o4b4o$4bo35b2o3$14b2o2$13bo3bo12bo$12bo4bo11bobo$11bo
13 | bobo6bo5bo3bo$10bobobo8b2o4bo3bo$8bo4bo8b2o6bo3bo$8bo3bo18bo3bo$32bobo
14 | $10b2o21bo!
--------------------------------------------------------------------------------
/app/src/main/res/drawable/book.xml:
--------------------------------------------------------------------------------
1 |
6 |
13 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_round_ballot_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
19 |
20 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/app/src/main/res/layout/sheet_blueprint_library_category.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_round_tune_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/copy.xml:
--------------------------------------------------------------------------------
1 |
6 |
13 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/assets/patterns/guns/period84glidergun.rle:
--------------------------------------------------------------------------------
1 | #N Period-84 glider gun
2 | #C https://conwaylife.com/wiki/P84_honey_farm_hassler
3 | #C https://www.conwaylife.com/patterns/period84glidergun.rle
4 | x = 35, y = 46, rule = B3/S23
5 | 7b2o8b2o$5bo2bo8b2o$5b2obob2o$6bobob2o$3b3obo18b2o2b2o$2bo3bobo17bobo
6 | 2bo$2bob2o2b3o12b2obob2o$b2obo3b3o12b2obobo3bo$2bobo5b2o15bob4o$2bob2o
7 | 3b3o6bo7bobo$b2obo5b2o4b2obo4b3o2b2o$4bo3b3o4bo3bo4b3o3bo$4b2o2b3o4bob
8 | 2o4b2o5bobo$6bobo7bo6b3o5b2o$2b4obo15b2o$2bo3bobob2o14b2o$5b2obob2o11b
9 | 2ob2o$5bo2bo14bo3b3o$7b2o11bo7b2o$13b2o3bobo6bo$14bo4b2o6b2o2b2o$11b3o
10 | 17bobo$11bo21bo$33b2o2$27bo$20bo4bobo$19bobo4b2o$19bobo$2o13bobo2bo$bo
11 | 15bo$bobo11b3o6b2o$2b2o16bo2bo2bo7bo$19bo3bob2o5bobo$19bo5bo7b2o$11bo
12 | 12bo$10bo12bo$9bo5bo$8b2obo3bo$8bo2bo2bo16b2o$9b2o6b3o11bobo$17bo15bo$
13 | 5b2o7bo2bobo13b2o$6bo6bobo$3b3o7bobo$3bo10bo!
--------------------------------------------------------------------------------
/app/src/main/res/layout/sheet_predefined_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_theme_picker.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/context_tool.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/size_indicator.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
9 |
12 |
16 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/upload.xml:
--------------------------------------------------------------------------------
1 |
6 |
13 |
20 |
27 |
28 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/external_link.xml:
--------------------------------------------------------------------------------
1 |
6 |
13 |
20 |
27 |
28 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/save.xml:
--------------------------------------------------------------------------------
1 |
6 |
13 |
20 |
27 |
28 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/random_cube.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/assets/patterns/preview/barge_synth.rle:
--------------------------------------------------------------------------------
1 | #N Barge_synth
2 | #O Mark D. Niemiec
3 | #C Glider synthesis of barges.
4 | #C https://www.conwaylife.com/ref/mniemiec/glider-3.htm
5 | x = 147, y = 86, rule = 23/3
6 | 49bo97b$49bobo95b$43bobo3b2o96b$44b2o101b$44bo84bo17b$3bo78bo41bobo2bo
7 | bo15b$b2o40b3o37bo40b2o3b2o16b$2b2o20bo20bo18bo16b3o20bo20bo18bo2b$23b
8 | obo18bo18bobo37bobo37bobob$bo3b2o17bobo37bobo10b2o4b3o18bobo19b2o16bob
9 | o$b2ob2o19bo39bo12b2o3bo21bo20bobo16bob$obo3bo70bo6bo41bo20b21$80bo66b
10 | $81bo65b$52bo26b3o65b$51bo95b$8b2o41b3o69bo23b$7bobo2b2o10bo24bo14bo
11 | 39bo19b2o18bo2b$9bob2o10bobo22b2o13bobo25b2o10bobo17b2o2bo15bobob$13bo
12 | 10bobo21bobo13bobo24bobo10bobo20bobo14bobo$25bo39bo21b2o2bo13bo21b2o
13 | 16bob$3b3o82b2o57b$5bo81bo59b$4bo142b$120b2o25b$121b2o24b$47b2o71bo26b
14 | $48b2o97b$47bo99b14$54bo92b$52b2o93b$53b2o26bo65b$80bo66b$80b3o64b$24b
15 | o39bo39bo42b$23bobo37bobo15bo21bobo41b$24bobo37bobo13b2o22bobo40b$25bo
16 | 39bo14bobo22bo41b3$41bobo103b$6bo34b2o104b$2bob2o36bo104b$obo2b2o140b$
17 | b2o37b3o104b$40bo106b$41bo105b4$3b2o98b2o42b$2bobo98bobo41b$4bo98bo!
--------------------------------------------------------------------------------
/app/src/main/res/drawable/globe.xml:
--------------------------------------------------------------------------------
1 |
6 |
13 |
20 |
27 |
28 |
--------------------------------------------------------------------------------
/app/src/main/assets/patterns/guns/period108glidergun.rle:
--------------------------------------------------------------------------------
1 | #N Period-108 glider gun
2 | #C https://conwaylife.com/wiki/R-pentomino_hasslers
3 | #C https://www.conwaylife.com/patterns/period108glidergun.rle
4 | x = 92, y = 92, rule = B3/S23
5 | 48b2o$48b2o$38b2o$39bo$39bobo$40b2o$49bo$48b3o$37b2o8bo2b2o$37bobo7b2o
6 | 3bo$38bo13b2o$52b3o$49b2obo$45bo4b2o$36bo7bobo$44bobo$37b2o6bo$37b2o3$
7 | 46b3o$45bo$37b2o$37b2o7b2o5$40bo21bo$28b3o6b2obo20b2o$29b3o4bo3bo20b2o
8 | $36bobo22bo$37bo4$60b2o15bo$11bo47bo2bo5b2o4b2o6b2o$10b2o31bo16bobo5b
9 | 2o4b2o5bobo5bo$9b4o29b3o37bo4b3o$8bo4bo28bo18b3o22bo$7b2o3b2o72b2o$2o
10 | 4b2o4bo38b2o$2o5bobo10bo31b2o$8b2o10bo2bo28bo23b2o$14b2o4bo2bo46bo4bo
11 | 2bo$13bo2bo4bo46bo2bo4b2o$14b2o23bo28bo2bo10b2o$38b2o31bo10bobo5b2o$
12 | 39b2o38bo4b2o4b2o$4b2o72b2o3b2o$5bo22b3o18bo28bo4bo$2b3o4bo37b3o29b4o$
13 | 2bo5bobo5b2o4b2o5bobo16bo31b2o$8b2o6b2o4b2o5bo2bo47bo$14bo15b2o4$54bo$
14 | 30bo22bobo$29b2o20bo3bo4b3o$29b2o20bob2o6b3o$29bo21bo5$44b2o7b2o$53b2o
15 | $46bo$43b3o3$53b2o$46bo6b2o$45bobo$45bobo7bo$40b2o4bo$39bob2o$37b3o$
16 | 38b2o13bo$39bo3b2o7bobo$40b2o2bo8b2o$41b3o$42bo$50b2o$50bobo$52bo$52b
17 | 2o$42b2o$42b2o!
--------------------------------------------------------------------------------
/app/src/main/java/leko/valmx/thegameoflife/SettingActivity.kt:
--------------------------------------------------------------------------------
1 | package leko.valmx.thegameoflife
2 |
3 | import android.content.Intent
4 | import android.net.Uri
5 | import androidx.appcompat.app.AppCompatActivity
6 | import android.os.Bundle
7 | import com.google.android.gms.oss.licenses.OssLicensesMenuActivity
8 | import kotlinx.android.synthetic.main.activity_setting.*
9 |
10 | class SettingActivity : AppCompatActivity() {
11 |
12 | val gitHubUrl = "https://github.com/val-mx/TheGameOfLife"
13 |
14 | override fun onCreate(savedInstanceState: Bundle?) {
15 | super.onCreate(savedInstanceState)
16 | setContentView(R.layout.activity_setting)
17 | btn_back.setOnClickListener {
18 | startActivity(Intent(this, MainActivity::class.java))
19 | }
20 | btn_git.setOnClickListener {
21 | val urlIntent = Intent(Intent.ACTION_VIEW)
22 | urlIntent.data = Uri.parse(gitHubUrl)
23 | startActivity(urlIntent)
24 | }
25 | btn_licenses.setOnClickListener {
26 | startActivity(Intent(this, OssLicensesMenuActivity::class.java))
27 | }
28 | }
29 | }
--------------------------------------------------------------------------------
/app/src/main/java/leko/valmx/thegameoflife/game/PreviewManager.kt:
--------------------------------------------------------------------------------
1 | package leko.valmx.thegameoflife.game
2 |
3 | import leko.valmx.thegameoflife.utils.blueprints.Blueprint
4 |
5 | class PreviewManager(val game: GameView) {
6 |
7 | fun init(sketch: Blueprint, stopTasks: Boolean = false) {
8 | game.gameColors.applyPreviewTheme()
9 | game.setOnTouchListener(null)
10 | val actorManager = game.cells
11 |
12 | val gridManager = game.gridManager
13 |
14 |
15 | val cells = sketch.cells
16 |
17 | val w = cells.size
18 | val h = cells[0].size
19 |
20 | gridManager.cellWidth = (game.width / w).toFloat()
21 |
22 |
23 | var baseH = 0
24 | val baseX = 0
25 |
26 |
27 |
28 | cells.forEachIndexed { x, yArray ->
29 |
30 | yArray.forEachIndexed { y, value ->
31 | if (value) actorManager.setCurrentlyAlive(x + baseX, y + baseH)
32 | }
33 |
34 | }
35 |
36 |
37 | android.os.Handler().postDelayed({
38 | game.animationManager.running = !stopTasks
39 | game.invalidate()
40 | }, 100L)
41 |
42 |
43 | }
44 |
45 | }
--------------------------------------------------------------------------------
/app/src/main/java/leko/valmx/thegameoflife/game/tools/EditTool.kt:
--------------------------------------------------------------------------------
1 | package leko.valmx.thegameoflife.game.tools
2 |
3 | import android.view.MotionEvent
4 | import leko.valmx.thegameoflife.game.GameView
5 | import leko.valmx.thegameoflife.game.InteractionManager
6 | import leko.valmx.thegameoflife.recyclers.ContextToolsAdapter
7 | import java.util.*
8 |
9 | class EditTool(val game: GameView) : InteractionManager.Interactable() {
10 |
11 | init {
12 | game.interactionManager.editMode = true
13 | }
14 |
15 | override fun getName(): String {
16 | return "Editing"
17 | }
18 |
19 | override fun onInteraction(motionEvent: MotionEvent, dereg: () -> Unit) {
20 |
21 | }
22 |
23 | override fun drawInteraction() {
24 |
25 | }
26 |
27 | override fun isNonMovementInteraction(event: MotionEvent): Boolean {
28 | return false
29 | }
30 |
31 | override fun onDeregister() {
32 | game.interactionManager.editMode = false
33 | }
34 |
35 | override fun onInteractionEnd(event: MotionEvent?) {
36 | }
37 |
38 | override fun addContextItems(items: LinkedList) {
39 | }
40 | }
--------------------------------------------------------------------------------
/app/src/main/res/navigation/nav_graph.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
17 |
18 |
23 |
24 |
27 |
28 |
--------------------------------------------------------------------------------
/app/src/main/res/navigation/nav_graph2.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
17 |
18 |
23 |
24 |
27 |
28 |
--------------------------------------------------------------------------------
/app/src/main/assets/rules/rules.txt:
--------------------------------------------------------------------------------
1 | B0123478/S34678$InverseLife//
2 | B1/S1$Gnarl//
3 | B1357/S1357$Replicator//
4 | B2/S$Seeds//
5 | B234/S$Serviettes//
6 | B25678/S5678$Iceballs//
7 | B3/S12$Flock//
8 | B3/S1234$Mazectric//
9 | B3/S12345$Maze//
10 | B3/S1237$SnowLife//
11 | B3/S124$Corrosion of Conformity//
12 | B3/S128$EightFlock//
13 | B3/S13$LowLife//
14 | B3/S238$EightLife//
15 | B3/S4567$Lifeguard 2//
16 | B3/S45678$Coral//
17 | B34/S34$3-4 Life//
18 | B34/S456$Bacteria//
19 | B345/S2$Blinkers//
20 | B345/S4567$Assimilation//
21 | B345/S5$Long Life//
22 | B3457/S4568$Gems//
23 | B34578/S456$Gems Minor//
24 | B35/S234578$Land Rush//
25 | B3567/S15678$Bugs//
26 | B35678/S4678$Holstein//
27 | B35678/S5678$Diamoeba//
28 | B357/S1358$Amoeba//
29 | B357/S238$Pseudo Life//
30 | B3578/S24678$Geology//
31 | B36/S12$HighFlock//
32 | B36/S125$2×2//
33 | B36/S128$IronFlock//
34 | B36/S23$HighLife//
35 | B36/S235$Blinker Life//
36 | B36/S238$IronLife//
37 | B36/S245$Logarithmic replicator rule//
38 | B368/S245$Morley//
39 | B5678/S45678$Vote//
40 | B4678/S35678$Vote 4/5//
41 | B45/S12345$Electrified Maze//
42 | B38/S23$Pedestrian Life//
43 | B45678/S2345$Walled cities//
44 | B45/S1235$Oscillators Rule//
45 | B56/S14568$Rings 'n' Slugs
--------------------------------------------------------------------------------
/app/src/main/res/values-de-rDE/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Game Of Life
4 | Einstellungen
5 | Lizenzen einsehen
6 | Einstellungen
7 | Source code auf GitHub
8 | Suche eine Regel aus
9 | Quelle
10 | Regeln
11 | Manipuliere die Regeln des Spiels
12 | Auf Werkseinstellungen
13 | Predefinierte Regeln
14 | Erstelle eine neue Blaupause
15 | Blaupausen
16 | Erstelle oder benutze Blaupausen
17 | wird geboren
18 | wird leben
19 | Wie soll die Blaupause benannt werden?
20 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/grid.xml:
--------------------------------------------------------------------------------
1 |
6 |
13 |
20 |
27 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/trash_2.xml:
--------------------------------------------------------------------------------
1 |
6 |
13 |
20 |
27 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_second.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
17 |
18 |
27 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_first.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
18 |
19 |
28 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app's APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Kotlin code style for this project: "official" or "obsolete":
19 | kotlin.code.style=official
20 | # Enables namespacing of each library's R class so that its R class includes only the
21 | # resources declared in the library itself and none from the library's dependencies,
22 | # thereby reducing the size of the R class for that library
23 | android.nonTransitiveRClass=true
--------------------------------------------------------------------------------
/app/src/main/java/leko/valmx/thegameoflife/game/tools/copypasta/Sketch.kt:
--------------------------------------------------------------------------------
1 | package leko.valmx.thegameoflife.game.tools.copypasta
2 |
3 | import android.util.Log
4 | import org.json.JSONObject
5 |
6 | class Sketch(var cells: Array>) {
7 |
8 | var name: String = "No Name given"
9 | var w = cells.size
10 | var h = cells[0].size
11 |
12 | fun toJsonString(): String {
13 | val json = JSONObject()
14 |
15 | json.put(WIDTH_ID, w)
16 | json.put(HEIGHT_ID, h)
17 |
18 | repeat(cells.size) { x ->
19 | repeat(cells[0].size) { y ->
20 | val isCell = cells[x][y]
21 | json.put("$x,$y", isCell)
22 | }
23 | }
24 |
25 | return json.toString()
26 | }
27 |
28 | companion object {
29 | val WIDTH_ID = "w"
30 | val HEIGHT_ID = "h"
31 | fun fromJson(jsonString: String?): Sketch? {
32 |
33 | Log.e("Parsing String","$jsonString")
34 |
35 | if (jsonString == "" || jsonString == null) return null
36 |
37 | val json = JSONObject(jsonString)
38 |
39 | val w = json.getInt(WIDTH_ID)
40 | val h = json.getInt(HEIGHT_ID)
41 |
42 | val cells = Array>(w) { x ->
43 | Array(h) { y ->
44 | json.getBoolean("$x,$y")
45 | }
46 | }
47 |
48 | return Sketch(cells)
49 | }
50 | }
51 |
52 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/settings.xml:
--------------------------------------------------------------------------------
1 |
6 |
13 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/java/leko/valmx/thegameoflife/recyclers/ContextToolsAdapter.kt:
--------------------------------------------------------------------------------
1 | package leko.valmx.thegameoflife.recyclers
2 |
3 | import android.annotation.SuppressLint
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.View.OnClickListener
7 | import android.view.ViewGroup
8 | import androidx.recyclerview.widget.RecyclerView
9 | import androidx.recyclerview.widget.RecyclerView.ViewHolder
10 | import kotlinx.android.synthetic.main.context_tool.view.*
11 | import leko.valmx.thegameoflife.R
12 | import java.util.LinkedList
13 |
14 | class ContextToolsAdapter(val data: LinkedList) :
15 | RecyclerView.Adapter() {
16 |
17 | class VH(view: View) : ViewHolder(view) {
18 |
19 | }
20 |
21 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VH {
22 | return VH(LayoutInflater.from(parent.context).inflate(R.layout.context_tool, parent, false))
23 | }
24 |
25 | @SuppressLint("UseCompatLoadingForDrawables")
26 | override fun onBindViewHolder(holder: VH, position: Int) {
27 |
28 | val itemView = holder.itemView
29 |
30 | val toolInfo = data[position]
31 |
32 | itemView.tool_img.setOnClickListener {
33 | toolInfo.onClick.onClick(it)
34 |
35 | }
36 | itemView.tool_img.setImageDrawable(holder.itemView.context.getDrawable(toolInfo.drawableId)!!)
37 |
38 | }
39 |
40 | override fun getItemCount(): Int = data.size
41 |
42 | class ContextTool(val drawableId: Int, val onClick: OnClickListener)
43 |
44 | }
--------------------------------------------------------------------------------
/app/src/main/java/leko/valmx/thegameoflife/recyclers/BlueprintCategoryAdapter.kt:
--------------------------------------------------------------------------------
1 | package leko.valmx.thegameoflife.recyclers
2 |
3 | import android.view.LayoutInflater
4 | import android.view.View
5 | import android.view.ViewGroup
6 | import androidx.recyclerview.widget.RecyclerView.Adapter
7 | import androidx.recyclerview.widget.RecyclerView.ViewHolder
8 | import kotlinx.android.synthetic.main.item_blueprint_selection.view.*
9 | import leko.valmx.thegameoflife.R
10 | import leko.valmx.thegameoflife.utils.AssetUtils
11 | import leko.valmx.thegameoflife.utils.PresetCategory
12 |
13 | class BlueprintCategoryAdapter(val onSelected: (PresetCategory) -> Unit) :
14 | Adapter() {
15 |
16 | private val data = AssetUtils.getPresetCategories()
17 |
18 | inner class VH(itemView: View) : ViewHolder(itemView) {
19 | fun bind(presetCategory: PresetCategory) {
20 | itemView.blueprintName.setText(presetCategory.name)
21 | itemView.setOnClickListener {
22 | onSelected(presetCategory)
23 | }
24 | }
25 | }
26 |
27 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VH {
28 | return VH(
29 | LayoutInflater.from(parent.context)
30 | .inflate(R.layout.item_preset_category, parent, false)
31 | )
32 | }
33 |
34 | override fun onBindViewHolder(holder: VH, position: Int) {
35 | val category = data[position]
36 | holder.bind(category)
37 | }
38 |
39 | override fun getItemCount(): Int = data.size
40 |
41 |
42 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/share_2.xml:
--------------------------------------------------------------------------------
1 |
6 |
13 |
20 |
27 |
34 |
41 |
42 |
--------------------------------------------------------------------------------
/app/src/main/java/leko/valmx/thegameoflife/views/ThemeView.kt:
--------------------------------------------------------------------------------
1 | package leko.valmx.thegameoflife.views
2 |
3 | import android.annotation.SuppressLint
4 | import android.content.Context
5 | import android.graphics.Canvas
6 | import android.graphics.Paint
7 | import android.graphics.Rect
8 | import android.graphics.RectF
9 | import android.util.AttributeSet
10 | import androidx.appcompat.widget.AppCompatImageView
11 | import androidx.core.graphics.toRectF
12 | import leko.valmx.thegameoflife.R
13 | import kotlin.random.Random
14 |
15 | class ThemeView(context: Context, attrs: AttributeSet?) : AppCompatImageView(context, attrs) {
16 |
17 | val gridColor = Paint().apply { color = resources.getColor(R.color.grid_1) }
18 | val backColor = Paint().apply { color = resources.getColor(R.color.back_1) }
19 | val cellColor = Paint().apply { color = resources.getColor(R.color.cell_1) }
20 |
21 | @SuppressLint("DrawAllocation")
22 | override fun onDraw(canvas: Canvas) {
23 | super.onDraw(canvas)
24 |
25 | val bgRect = RectF(0F, 0F, width.toFloat(), height.toFloat())
26 |
27 |
28 | canvas.drawCircle(bgRect.centerX(),bgRect.centerX(), bgRect.width()/2, backColor)
29 |
30 | val dxy = width / 3F
31 |
32 |
33 | val inset = width * .19F
34 |
35 | val rect2 = Rect(0, 0, width, height).toRectF()
36 |
37 | rect2.inset(inset, inset)
38 |
39 | canvas.drawCircle(rect2.centerX(),rect2.centerX(), rect2.width()/2, cellColor)
40 |
41 | }
42 |
43 | override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
44 | super.onMeasure(widthMeasureSpec, widthMeasureSpec)
45 | }
46 |
47 |
48 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_blueprint_info_website.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
15 |
16 |
24 |
25 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/java/leko/valmx/thegameoflife/game/tools/AutoPlayTool.kt:
--------------------------------------------------------------------------------
1 | package leko.valmx.thegameoflife.game.tools
2 |
3 | import android.os.Handler
4 | import android.view.MotionEvent
5 | import leko.valmx.thegameoflife.R
6 | import leko.valmx.thegameoflife.game.GameView
7 | import leko.valmx.thegameoflife.game.InteractionManager
8 | import leko.valmx.thegameoflife.recyclers.ContextToolsAdapter
9 | import java.util.*
10 |
11 | class AutoPlayTool(val game: GameView) : InteractionManager.Interactable(), Runnable {
12 |
13 | private val handler = Handler()
14 |
15 | var deltaT = 800L
16 | set(value) {
17 | if (value < 0) return
18 | if (value > 1500) return
19 | field = value
20 | }
21 | var runMe = true
22 |
23 | init {
24 | handler.postDelayed(this, deltaT)
25 | }
26 |
27 | override fun onInteraction(motionEvent: MotionEvent, dereg: () -> Unit) {
28 |
29 | }
30 |
31 |
32 | override fun isNonMovementInteraction(event: MotionEvent): Boolean {
33 | return false
34 | }
35 |
36 | override fun onDeregister() {
37 | runMe = false
38 | }
39 |
40 | override fun getName() = "Simulating..."
41 | override fun onInteractionEnd(event: MotionEvent?) {
42 |
43 | }
44 |
45 | override fun addContextItems(items: LinkedList) {
46 | items.add(ContextToolsAdapter.ContextTool(R.drawable.chevron_left) { deltaT += 80 })
47 | items.add(ContextToolsAdapter.ContextTool(R.drawable.chevron_right) { deltaT -= 80 })
48 | }
49 |
50 | override fun run() {
51 | if (!runMe) return
52 | game.cells.calculateNextGenAsync()
53 | handler.postDelayed(this, deltaT)
54 | }
55 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_blueprint_info_misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
15 |
16 |
25 |
26 |
35 |
36 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/sheet_save_blueprint.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
17 |
18 |
26 |
27 |
28 |
39 |
--------------------------------------------------------------------------------
/app/src/main/java/leko/valmx/thegameoflife/game/AnimationManager.kt:
--------------------------------------------------------------------------------
1 | package leko.valmx.thegameoflife.game
2 |
3 | import android.os.Handler
4 | import leko.valmx.thegameoflife.game.animations.Animation
5 | import java.util.*
6 | import kotlin.math.roundToLong
7 |
8 |
9 | class AnimationManager(val gameView: GameView) : Runnable {
10 |
11 | companion object
12 |
13 | var running = false
14 |
15 | var freezeLength = 1000 / 240F
16 |
17 | val animations = LinkedList()
18 |
19 | fun init() {
20 | start()
21 | }
22 |
23 | private fun start() {
24 | running = true
25 |
26 | Handler().postDelayed(this, freezeLength.roundToLong())
27 | }
28 |
29 | override fun run() {
30 |
31 | if (!running) return
32 |
33 | val startTimeStamp = System.currentTimeMillis()
34 |
35 | val drawManager = gameView.drawManager
36 |
37 | drawManager.draw()
38 |
39 | var toBeDeleted = LinkedList()
40 |
41 | animations.forEach {
42 |
43 | if (it.counter == 0L) it.onAnimationStart()
44 |
45 | it.counter += freezeLength.toLong()
46 | var av = Math.pow((1F * it.counter / it.animLength).toDouble(), 2.0).toFloat()
47 | if (av > 1) av = 1F
48 |
49 | it.onAnimate(av)
50 |
51 | if (it.counter > it.animLength) {
52 | it.onAnimationFinished()
53 | toBeDeleted.add(it)
54 | return@forEach
55 | }
56 |
57 |
58 | }
59 | animations.removeAll(toBeDeleted)
60 |
61 |
62 |
63 | gameView.invalidate()
64 |
65 | val dt = System.currentTimeMillis() - startTimeStamp
66 |
67 | Handler().postDelayed(this, freezeLength.roundToLong() - dt / 2)
68 | }
69 |
70 |
71 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/app/src/main/java/leko/valmx/thegameoflife/recyclers/RulePresetPickerAdapter.kt:
--------------------------------------------------------------------------------
1 | package leko.valmx.thegameoflife.recyclers
2 |
3 | import android.content.Context
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import androidx.recyclerview.widget.RecyclerView.Adapter
8 | import androidx.recyclerview.widget.RecyclerView.ViewHolder
9 | import kotlinx.android.synthetic.main.item_rule_selection.view.*
10 | import leko.valmx.thegameoflife.R
11 | import leko.valmx.thegameoflife.game.utils.GameRuleHelper
12 | import java.util.LinkedList
13 |
14 | class RulePresetPickerAdapter(
15 | ctx: Context,
16 | val listener: RuleSelectedListener,
17 | val onSelection: () -> Unit
18 | ) : Adapter() {
19 |
20 | val rules = GameRuleHelper(ctx).loadPresetRules()
21 | val ruleNames = LinkedList(rules.keys)
22 |
23 |
24 | class VH(itemView: View) : ViewHolder(itemView)
25 |
26 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VH {
27 | return VH(
28 | LayoutInflater.from(parent.context)
29 | .inflate(R.layout.item_rule_selection, parent, false)
30 | )
31 | }
32 |
33 | override fun onBindViewHolder(holder: VH, position: Int) {
34 |
35 | val name = ruleNames[position]
36 |
37 | holder.itemView.setOnClickListener {
38 | listener.onRuleSelected(GameRuleHelper.RuleSet(rules[name]!!))
39 | onSelection()
40 | }
41 |
42 | holder.itemView.ruleName.text = name
43 | holder.itemView.rule_str.text = rules[name]
44 |
45 | }
46 |
47 | override fun getItemCount(): Int {
48 | return ruleNames.size
49 | }
50 |
51 | interface RuleSelectedListener {
52 | fun onRuleSelected(rule: GameRuleHelper.RuleSet)
53 | }
54 |
55 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_rule_selection.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
20 |
21 |
29 |
30 |
40 |
41 |
--------------------------------------------------------------------------------
/app/src/main/java/leko/valmx/thegameoflife/recyclers/RuleSheetAdapter.kt:
--------------------------------------------------------------------------------
1 | package leko.valmx.thegameoflife.recyclers
2 |
3 | import android.content.Context
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import androidx.recyclerview.widget.RecyclerView.Adapter
8 | import androidx.recyclerview.widget.RecyclerView.ViewHolder
9 | import kotlinx.android.synthetic.main.item_rule_tweak.view.*
10 | import leko.valmx.thegameoflife.R
11 | import leko.valmx.thegameoflife.game.utils.GameRuleHelper
12 |
13 | class RuleSheetAdapter(ctx: Context, val ruleSet: GameRuleHelper.RuleSet) : Adapter() {
14 |
15 |
16 | class VH(item: View) : ViewHolder(item) {
17 |
18 | fun bind(rules: GameRuleHelper.RuleSet, position: Int) {
19 | itemView.tweak_title.text = "${position + 1} Neighbours"
20 |
21 | itemView.check_survive.isChecked = rules.willSurvive(position+1)
22 | itemView.check_born.isChecked = rules.willBeBorn(position+1)
23 |
24 |
25 |
26 | itemView.check_born.setOnCheckedChangeListener { buttonView, isChecked ->
27 | rules.setBorn(position, isChecked)
28 | }
29 |
30 | itemView.check_survive.setOnCheckedChangeListener { buttonView, isChecked ->
31 | rules.setSurvive(position, isChecked)
32 | }
33 | }
34 |
35 | }
36 |
37 |
38 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VH {
39 | return VH(
40 | LayoutInflater.from(parent.context).inflate(R.layout.item_rule_tweak, parent, false)
41 | )
42 | }
43 |
44 | override fun onBindViewHolder(holder: VH, position: Int) {
45 | holder.bind(ruleSet, position)
46 | }
47 |
48 | override fun getItemCount(): Int {
49 | return 8
50 | }
51 | }
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFBB86FC
4 | #FF6200EE
5 | #FF3700B3
6 | #FF03DAC5
7 | #FF018786
8 | #FF000000
9 | #FFFFFFFF
10 | #E2E2E2
11 |
12 |
13 |
14 | #FEAA15
15 | #FEFEFE
16 | #000000
17 | #393939
18 | #FFFFFF
19 | #A5A5A5
20 | #77E2E2E2
21 |
22 | #3949AB
23 | #FFFFFF
24 | #3B3B3B
25 | #393939
26 | #FFFFFF
27 |
28 | #003566
29 | #ffd60a
30 | #FFFFFF
31 | #001d3d
32 | #ffc300
33 | #003566
34 | #fb8b24
35 |
36 | #F95738
37 | #FFFFFF
38 | #90BDE8
39 | #393939
40 | #FFFFFF
41 |
42 | #FEFEFE
43 | #847FFE
44 | #FEAA15
45 | #59686868
46 | #536DFE
47 |
--------------------------------------------------------------------------------
/app/src/main/java/leko/valmx/thegameoflife/game/GameView.kt:
--------------------------------------------------------------------------------
1 | package leko.valmx.thegameoflife.game
2 |
3 | import android.content.Context
4 | import android.graphics.Bitmap
5 | import android.graphics.Canvas
6 | import android.graphics.drawable.BitmapDrawable
7 | import android.util.AttributeSet
8 | import leko.valmx.thegameoflife.MainActivity
9 | import leko.valmx.thegameoflife.game.tools.SelectionTool
10 |
11 | class GameView(context: Context?, attrs: AttributeSet?) :
12 | androidx.appcompat.widget.AppCompatImageView(context!!, attrs) {
13 |
14 | var initialized = false
15 |
16 | val canvas = Canvas()
17 | val gridManager = GridManager(this)
18 | val animationManager = AnimationManager(this)
19 | val gameColors = GameColors(this)
20 | val cells = Cells(context)
21 | val interactionManager = InteractionManager(this)
22 | val drawManager =
23 | DrawManager(canvas, gridManager, cells, gameColors, interactionManager)
24 | val toolsManager = SelectionTool(this)
25 | val previewManager = PreviewManager(this)
26 | val feedBackManager = FeedBackManager(this)
27 |
28 | lateinit var mainActivity: MainActivity
29 |
30 |
31 | override fun onDraw(canvas: Canvas) {
32 | super.onDraw(canvas)
33 | if (!initialized) {
34 | init()
35 | initialized = true
36 | }
37 | }
38 |
39 | fun init(onInitilized: (() -> Unit?)? = null) {
40 | initialized = true
41 |
42 | val bm = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
43 | canvas.setBitmap(bm)
44 | background = BitmapDrawable(bm)
45 |
46 | setOnTouchListener(interactionManager)
47 |
48 | gridManager.init()
49 | gameColors.init()
50 | gameColors.loadSavedTheme(context)
51 | animationManager.init()
52 |
53 | onInitilized?.let { it() }
54 | }
55 | }
--------------------------------------------------------------------------------
/app/src/main/assets/patterns/preview/gliderloop.rle:
--------------------------------------------------------------------------------
1 | #N Glider loop
2 | #C A pattern in which two gliders are bounced back and forth along an
3 | #C ever-lengthening track.
4 | #C www.conwaylife.com/wiki/index.php?title=Glider_loop
5 | x = 73, y = 150, rule = b3/s23
6 | 45bo27b$37b3o5bo27b$36bo2b2o3bobo26b$35bo5bo3bo27b$41bo3bo27b$36b2o2bo
7 | 32b$25b2o11b2o33b$25b2o46b6$61bo11b$17b2o40b2ob2o9b$17b2o42bo11b3$59b
8 | 2o12b$58bo2bo11b$51bo5bo3b2o10b$51bo5bo4bo10b$9b2o40bo6bo3bo10b$9b2o
9 | 37bob3obo3bo2bo11b$48b5obo5bo12b$48bobo22b$52b2o17bob$52b2o9b3o5bob$
10 | 52bo9bo2b2o3bobo$51b2o8bo5bo3bob$46b2o3bo15bo3bob$17b3o31bo10b2o2bo6b$
11 | 20bo29b2obo10b2o7b$15b2o4bo30bo20b$18bo3bo50b$14bo4bo2bo50b$14bo3bo3bo
12 | 50b$14b3obob2o51b$18bo54b$14b4o7b3o45b$14b2o8bo3bo44b$24bo4bo28bo14b$
13 | 26bo3bo25b2o9b2o4b$23b3obo2bo24b2o8b3obo3b$22bo7bo23bo10bo3bo3b$22bobo
14 | 3bo26b5o5bob2o4b$21b2obo3bo27bo10bo5b$21b2ob3o46b5$63b2o8b$63b2o8b4$
15 | 43b3o27b$46bo26b$41b2o4bo25b$44bo3bo6b2o16b$40bo4bo2bo6b2o16b$40bo3bo
16 | 3bo24b$40b3obob2o25b$44bo28b$40b4o29b$40b2o31b2$47b2o24b$47b2o24b2$33b
17 | o39b$33bobo37b$33b2o38b3$38b2o33b$37bobo33b$39bo33b2$24b2o47b$24b2o47b
18 | 2$31b2o40b$29b4o40b$28bo44b$25b2obob3o40b$24bo3bo3bo40b$16b2o6bo2bo4bo
19 | 40b$16b2o6bo3bo44b$25bo4b2o41b$26bo46b$27b3o43b4$8b2o63b$8b2o63b5$46b
20 | 3ob2o21b$5bo10bo27bo3bob2o21b$4b2obo5b5o26bo3bobo22b$3bo3bo10bo23bo7bo
21 | 22b$3bob3o8b2o24bo2bob3o23b$4b2o9b2o25bo3bo26b$14bo28bo4bo24b$44bo3bo
22 | 8b2o14b$45b3o7b4o14b$54bo18b$51b2obob3o14b$50bo3bo3bo14b$50bo2bo4bo14b
23 | $50bo3bo18b$20bo30bo4b2o15b$7b2o10bob2o29bo20b$6bo2b2o10bo31b3o17b$bo
24 | 3bo15bo3b2o46b$bo3bo5bo8b2o51b$obo3b2o2bo9bo52b$bo5b3o9b2o52b$bo17b2o
25 | 52b$22bobo48b$12bo5bob5o48b$11bo2bo3bob3obo37b2o9b$10bo3bo6bo40b2o9b$
26 | 10bo4bo5bo51b$10b2o3bo5bo51b$11bo2bo58b$12b2o59b3$11bo42b2o17b$9b2ob2o
27 | 40b2o17b$11bo61b6$46b2o25b$33b2o11b2o25b$32bo2b2o36b$27bo3bo41b$27bo3b
28 | o5bo35b$26bobo3b2o2bo36b$27bo5b3o37b$27bo!
--------------------------------------------------------------------------------
/app/src/main/java/leko/valmx/thegameoflife/sheets/BlueprintPresetSelectCategorySheet.kt:
--------------------------------------------------------------------------------
1 | package leko.valmx.thegameoflife.sheets
2 |
3 | import android.content.Context
4 | import android.os.Bundle
5 | import android.view.View
6 | import androidx.recyclerview.widget.LinearLayoutManager
7 | import com.maxkeppeler.sheets.core.Sheet
8 | import com.maxkeppeler.sheets.core.SheetStyle
9 | import kotlinx.android.synthetic.main.sheet_blueprint_library_category.*
10 | import leko.valmx.thegameoflife.R
11 | import leko.valmx.thegameoflife.game.GameView
12 | import leko.valmx.thegameoflife.recyclers.BlueprintCategoryAdapter
13 | import leko.valmx.thegameoflife.utils.AssetUtils
14 | import leko.valmx.thegameoflife.utils.PresetCategory
15 |
16 | class BlueprintPresetSelectCategorySheet(context: Context, val gameView: GameView) : Sheet() {
17 | init {
18 | show(context)
19 | }
20 |
21 | private fun show(ctx: Context) {
22 | this.windowContext = ctx
23 | this.width = null
24 | displayPositiveButton(false)
25 | style(SheetStyle.DIALOG)
26 | title("Select a category")
27 |
28 | onNegative("BACK") {
29 | MoreOptionsSheet(requireContext(),gameView)
30 | }
31 |
32 | this.show()
33 | }
34 |
35 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
36 | super.onViewCreated(view, savedInstanceState)
37 | presets_category_recycler.layoutManager = LinearLayoutManager(requireContext())
38 | presets_category_recycler.adapter = BlueprintCategoryAdapter { category: PresetCategory ->
39 | BlueprintPresetSelectionSheet(
40 | gameView,
41 | category
42 | )
43 | dismiss()
44 | }
45 | }
46 |
47 | override fun onCreateLayoutView(): View {
48 | return View.inflate(context, R.layout.sheet_blueprint_library_category, null)
49 | }
50 |
51 | }
--------------------------------------------------------------------------------
/app/src/main/java/leko/valmx/thegameoflife/views/ConwaysCellStateView.kt:
--------------------------------------------------------------------------------
1 | package leko.valmx.thegameoflife.views
2 |
3 | import android.content.Context
4 | import android.graphics.Bitmap
5 | import android.graphics.Canvas
6 | import android.graphics.Paint
7 | import android.graphics.drawable.BitmapDrawable
8 | import android.util.AttributeSet
9 | import android.view.View
10 | import leko.valmx.thegameoflife.R
11 | import java.util.LinkedList
12 |
13 | class ConwaysCellStateView(context: Context?, attrs: AttributeSet?) : View(context, attrs) {
14 |
15 | private var bm: Bitmap? = null
16 | private lateinit var canvas: Canvas
17 | private lateinit var currentTutorialState: TutorialState
18 |
19 |
20 | private val allStates = LinkedList()
21 |
22 | init {
23 |
24 | val tut1 = TutorialState("Thank you for downloading this App!")
25 |
26 | val state1 = tut1.states
27 | state1.add(State(0, 0, resources.getColor(R.color.cell_1)))
28 | state1.add(State(0, 0, resources.getColor(R.color.cell_1)))
29 |
30 | currentTutorialState = allStates.first
31 |
32 | }
33 |
34 | override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
35 | super.onLayout(changed, left, top, right, bottom)
36 | init()
37 | }
38 |
39 | private fun init() {
40 | if (bm != null) return
41 |
42 | bm = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
43 | canvas = Canvas(bm!!)
44 | background = BitmapDrawable(bm)
45 | }
46 |
47 | fun nextState() {
48 |
49 | }
50 |
51 | fun drawState() {
52 | val currentStates = currentTutorialState.states
53 | val p = Paint()
54 | p.color
55 |
56 | }
57 |
58 | class State(val x: Int, val y: Int, val color: Int)
59 |
60 | class TutorialState(val description: String) {
61 | val states = LinkedList()
62 | }
63 |
64 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_preset_category.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
23 |
24 |
33 |
34 |
42 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_rule_tweak.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
14 |
15 |
25 |
26 |
36 |
37 |
47 |
48 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
17 |
21 |
24 |
25 |
30 |
33 |
34 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_intro.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
14 |
15 |
24 |
25 |
30 |
31 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/app/src/main/java/leko/valmx/thegameoflife/recyclers/BlueprintInfoRecycler.kt:
--------------------------------------------------------------------------------
1 | package leko.valmx.thegameoflife.recyclers
2 |
3 | import android.util.Patterns
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import androidx.recyclerview.widget.RecyclerView.Adapter
8 | import androidx.recyclerview.widget.RecyclerView.ViewHolder
9 | import kotlinx.android.synthetic.main.item_blueprint_info_misc.view.*
10 | import leko.valmx.thegameoflife.R
11 | import leko.valmx.thegameoflife.utils.blueprints.Blueprint
12 |
13 | class BlueprintInfoRecycler(val blueprint: Blueprint) : Adapter() {
14 |
15 | private val comments = blueprint.comments
16 | private val websitePattern = Regex(".*www.*")
17 |
18 | private val viewTypeWebsite = 1
19 |
20 | open class VH(itemView: View) : ViewHolder(itemView) {
21 | open fun bind(comment: String) {
22 | itemView.content.text = comment
23 | }
24 | }
25 |
26 | class WebsiteInfoVH(itemView: View) : VH(itemView) {
27 | }
28 |
29 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VH {
30 | val inflater = LayoutInflater.from(parent.context)
31 | return when (viewType) {
32 | viewTypeWebsite -> WebsiteInfoVH(
33 | inflater.inflate(
34 | R.layout.item_blueprint_info_website,
35 | parent,
36 | false
37 | )
38 | )
39 | else -> VH(
40 | inflater.inflate(R.layout.item_blueprint_info_misc, parent, false)
41 | )
42 | }
43 |
44 | }
45 |
46 | override fun onBindViewHolder(holder: VH, position: Int) {
47 | holder.bind(comments[position])
48 | }
49 |
50 | override fun getItemViewType(position: Int): Int {
51 |
52 | val s = comments[position]
53 |
54 | if (s.contains(".com")) {
55 | return viewTypeWebsite;
56 | }
57 |
58 | return 0;
59 | }
60 |
61 | override fun getItemCount(): Int {
62 | return comments.size
63 |
64 | }
65 |
66 | }
--------------------------------------------------------------------------------
/app/src/main/java/leko/valmx/thegameoflife/sheets/BlueprintInfoSheet.kt:
--------------------------------------------------------------------------------
1 | package leko.valmx.thegameoflife.sheets
2 |
3 | import android.content.Context
4 | import android.os.Bundle
5 | import android.os.Handler
6 | import android.view.View
7 | import androidx.recyclerview.widget.LinearLayoutManager
8 | import com.maxkeppeler.sheets.core.Sheet
9 | import com.maxkeppeler.sheets.core.SheetStyle
10 | import kotlinx.android.synthetic.main.sheet_blueptint_more_info.*
11 | import kotlinx.android.synthetic.main.sheet_rules.*
12 | import leko.valmx.thegameoflife.R
13 | import leko.valmx.thegameoflife.game.GameView
14 | import leko.valmx.thegameoflife.game.utils.GameRuleHelper
15 | import leko.valmx.thegameoflife.recyclers.BlueprintInfoRecycler
16 | import leko.valmx.thegameoflife.recyclers.RulePresetPickerAdapter
17 | import leko.valmx.thegameoflife.recyclers.RuleSheetAdapter
18 | import leko.valmx.thegameoflife.utils.blueprints.Blueprint
19 |
20 |
21 | class BlueprintInfoSheet(val blueprint: Blueprint) : Sheet() {
22 | fun show(ctx: Context) {
23 | this.windowContext = ctx
24 | positiveText = "Apply"
25 | show()
26 | style(SheetStyle.DIALOG)
27 | title("More Info")
28 | isCancelable = false
29 | displayPositiveButton(false)
30 | onNegative("Back")
31 |
32 | }
33 |
34 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
35 | super.onViewCreated(view, savedInstanceState)
36 | /*preview.init {
37 | preview.previewManager.init(blueprint, true)
38 | }*/
39 | info_recycler.layoutManager = LinearLayoutManager(context)
40 | info_recycler.adapter = BlueprintInfoRecycler(blueprint)
41 |
42 | blueprint_author.text = blueprint.author
43 | blueprint_name.text = blueprint.name
44 | blueprint_rule.text = "${blueprint.width}x${blueprint.height}"
45 | Handler().postDelayed({
46 | preview.previewManager.init(blueprint, true)
47 |
48 | }, 100L)
49 | }
50 |
51 | override fun onCreateLayoutView(): View {
52 | return View.inflate(context, R.layout.sheet_blueptint_more_info, null)
53 | }
54 |
55 | }
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.application'
3 | id 'org.jetbrains.kotlin.android'
4 | id 'com.google.android.gms.oss-licenses-plugin'
5 | }
6 |
7 | android {
8 | namespace 'leko.valmx.thegameoflife'
9 | compileSdk 34
10 |
11 | apply plugin: 'com.android.application'
12 | apply plugin: 'kotlin-android'
13 | apply plugin: 'kotlin-android-extensions'
14 |
15 | defaultConfig {
16 | applicationId "leko.valmx.thegameoflife"
17 | minSdk 23
18 | targetSdk 33
19 | versionCode 16
20 | versionName "0.16"
21 |
22 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
23 | }
24 |
25 | buildTypes {
26 | release {
27 | minifyEnabled false
28 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
29 | }
30 | }
31 | compileOptions {
32 | sourceCompatibility JavaVersion.VERSION_11
33 | targetCompatibility JavaVersion.VERSION_11
34 | }
35 | kotlinOptions {
36 | jvmTarget = '1.8'
37 | }
38 | buildFeatures {
39 | viewBinding true
40 | }
41 | }
42 |
43 | dependencies {
44 | implementation("com.google.android.gms:play-services-oss-licenses:17.0.0")
45 | implementation 'androidx.core:core-ktx:1.9.0'
46 | implementation 'androidx.appcompat:appcompat:1.6.0'
47 | implementation 'com.google.android.material:material:1.8.0'
48 | implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
49 | implementation 'androidx.navigation:navigation-fragment-ktx:2.5.3'
50 | implementation 'androidx.navigation:navigation-ui-ktx:2.5.3'
51 | implementation 'com.ramotion.fluidslider:fluid-slider:0.3.1'
52 | testImplementation 'junit:junit:4.13.2'
53 |
54 | implementation 'com.maxkeppeler.sheets:core:2.3.0'
55 | implementation 'com.maxkeppeler.sheets:option:2.3.0'
56 | implementation 'com.maxkeppeler.sheets:input:2.3.0'
57 | implementation 'com.maxkeppeler.sheets:info:2.3.0'
58 |
59 | androidTestImplementation 'androidx.test.ext:junit:1.1.4'
60 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.0'
61 | }
--------------------------------------------------------------------------------
/app/src/main/java/leko/valmx/thegameoflife/game/DrawManager.kt:
--------------------------------------------------------------------------------
1 | package leko.valmx.thegameoflife.game
2 |
3 | import android.graphics.Canvas
4 | import android.graphics.Paint
5 | import android.graphics.RectF
6 |
7 | class DrawManager(
8 | private val canvas: Canvas,
9 | private val gridManager: GridManager,
10 | private val actorManager: Cells,
11 | private val colors: GameColors,
12 | private val interactionManager: InteractionManager
13 | ) {
14 |
15 | fun draw() {
16 | clearCanvas(canvas)
17 | drawUsableAreaIndicator()
18 | drawAliveCells()
19 | drawCurrentTool()
20 | }
21 |
22 | private fun drawUsableAreaIndicator() {
23 | val gameArena = getGameArenaBounds()
24 |
25 | adjustForCurrentOffset(gameArena)
26 | canvas.drawRoundRect(gameArena, 10F, 10F, colors.ui)
27 | }
28 |
29 | private fun drawAliveCells() {
30 | val cells = actorManager.aliveCells
31 | cells.forEach { cell ->
32 | drawCellAt(gridManager.getCellRect(cell.x, cell.y), colors.cell)
33 | }
34 | }
35 |
36 | private fun adjustForCurrentOffset(gameArena: RectF) {
37 | gameArena.offset(-gridManager.xOffset, -gridManager.yOffset)
38 | }
39 |
40 | private fun clearCanvas(canvas: Canvas) {
41 | canvas.drawPaint(colors.background)
42 | }
43 |
44 | private fun getGameArenaBounds(): RectF {
45 | return RectF(
46 | 0F,
47 | 0F,
48 | gridManager.cellWidth * Cells.mapSizeX,
49 | gridManager.cellWidth * Cells.mapSizeY
50 | ).apply { inset(-gridManager.cellWidth, -gridManager.cellWidth) }
51 | }
52 |
53 | private fun drawCurrentTool() {
54 | interactionManager.registeredInteraction?.drawInteraction()
55 | }
56 |
57 | private fun drawCellAt(rect: RectF, paint: Paint) {
58 | canvas.drawRect(rect, paint)
59 | }
60 |
61 |
62 | fun drawCellAt(x: Float, y: Float) {
63 |
64 | val cellWidth = gridManager.cellWidth
65 |
66 | canvas.drawRect(
67 | RectF(x, y, x + cellWidth, y + cellWidth),
68 | colors.cell
69 | )
70 | }
71 |
72 |
73 | }
--------------------------------------------------------------------------------
/app/src/main/java/leko/valmx/thegameoflife/sheets/RulePresetSelectionSheet.kt:
--------------------------------------------------------------------------------
1 | package leko.valmx.thegameoflife.sheets
2 |
3 | import android.content.Context
4 | import android.os.Bundle
5 | import android.view.View
6 | import androidx.recyclerview.widget.GridLayoutManager
7 | import androidx.recyclerview.widget.LinearLayoutManager
8 | import com.maxkeppeler.sheets.core.IconButton
9 | import com.maxkeppeler.sheets.core.Sheet
10 | import com.maxkeppeler.sheets.core.SheetStyle
11 | import kotlinx.android.synthetic.main.sheet_predefined_selector.*
12 | import leko.valmx.thegameoflife.R
13 | import leko.valmx.thegameoflife.game.GameView
14 | import leko.valmx.thegameoflife.recyclers.RulePresetPickerAdapter
15 |
16 | class RulePresetSelectionSheet(context: Context, val gameView: GameView, val ruleSelectedListener: RulePresetPickerAdapter.RuleSelectedListener) : Sheet(){
17 | fun show(ctx: Context) {
18 | this.windowContext = ctx
19 | this.width = null
20 |
21 |
22 | this.show()
23 | title("Select a rule")
24 | style(SheetStyle.DIALOG)
25 |
26 | withIconButton(IconButton(R.drawable.external_link)) {
27 | SourceSheet(
28 | requireContext(),
29 | "https://conwaylife.com/wiki/List_of_Life-like_cellular_automata",
30 | "16.12.2022",
31 | "GNU Free Documentation License 1.2",
32 | "https://www.gnu.org/licenses/fdl-1.3.html"
33 | )
34 | }
35 |
36 |
37 | displayPositiveButton(false)
38 |
39 | }
40 |
41 | override fun onCreate(savedInstanceState: Bundle?) {
42 | super.onCreate(savedInstanceState)
43 |
44 | }
45 |
46 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
47 | super.onViewCreated(view, savedInstanceState)
48 |
49 | presets_recycler.layoutManager = GridLayoutManager(context,2)
50 | presets_recycler.adapter = RulePresetPickerAdapter(requireContext(), ruleSelectedListener) {
51 | dismiss()
52 | }
53 | }
54 |
55 | override fun onCreateLayoutView(): View {
56 | return View.inflate(context, R.layout.sheet_predefined_selector, null)
57 | }
58 |
59 |
60 | }
--------------------------------------------------------------------------------
/app/src/main/java/leko/valmx/thegameoflife/sheets/SourceSheet.kt:
--------------------------------------------------------------------------------
1 | package leko.valmx.thegameoflife.sheets
2 |
3 | import android.content.Context
4 | import android.content.Intent
5 | import android.net.Uri
6 | import android.os.Bundle
7 | import android.view.View
8 | import androidx.recyclerview.widget.LinearLayoutManager
9 | import com.maxkeppeler.sheets.core.Sheet
10 | import kotlinx.android.synthetic.main.sheet_rules.*
11 | import kotlinx.android.synthetic.main.sheet_source.*
12 | import leko.valmx.thegameoflife.R
13 | import leko.valmx.thegameoflife.game.GameView
14 | import leko.valmx.thegameoflife.game.utils.GameRuleHelper
15 | import leko.valmx.thegameoflife.recyclers.RulePresetPickerAdapter
16 | import leko.valmx.thegameoflife.recyclers.RuleSheetAdapter
17 |
18 | class SourceSheet(
19 | context: Context,
20 | private val urlString: String,
21 | private val time: String,
22 | private val licenceName: String,
23 | private val licenceUrl: String
24 | ) : Sheet() {
25 |
26 | init {
27 | show(context)
28 | }
29 |
30 | private fun show(ctx: Context) {
31 | this.windowContext = ctx
32 | this.width = null
33 |
34 | displayNegativeButton(false)
35 |
36 | showsDialog = true
37 |
38 | this.show()
39 |
40 | }
41 |
42 | override fun onCreate(savedInstanceState: Bundle?) {
43 | super.onCreate(savedInstanceState)
44 |
45 | }
46 |
47 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
48 | super.onViewCreated(view, savedInstanceState)
49 | url.text = urlString
50 | licence.text = licenceName
51 |
52 | url_btn.setOnClickListener {
53 | val urlIntent = Intent(Intent.ACTION_VIEW)
54 | urlIntent.data = Uri.parse(urlString)
55 | startActivity(urlIntent)
56 | }
57 |
58 | licence_btn.setOnClickListener {
59 | val urlIntent = Intent(Intent.ACTION_VIEW)
60 | urlIntent.data = Uri.parse(licenceUrl)
61 | startActivity(urlIntent)
62 | }
63 |
64 | timestamp.text = "Retrieved on: $time"
65 | }
66 |
67 |
68 | override fun onCreateLayoutView(): View {
69 | return View.inflate(context, R.layout.sheet_source, null)
70 | }
71 |
72 | }
--------------------------------------------------------------------------------
/app/src/main/java/leko/valmx/thegameoflife/game/tools/copypasta/SketchLoadSaver.kt:
--------------------------------------------------------------------------------
1 | package leko.valmx.thegameoflife.game.tools.copypasta
2 |
3 | import android.content.Context
4 | import android.content.Context.MODE_PRIVATE
5 | import android.util.Log
6 | import androidx.core.content.edit
7 | import java.util.LinkedList
8 |
9 | class SketchLoadSaver(val context: Context) {
10 |
11 | companion object {
12 | const val PREF_ID = "CWGOL_SKETCHES"
13 | const val NAMES_ID = "NAMES"
14 | }
15 |
16 | // WTF
17 |
18 | val prefs = context.getSharedPreferences(PREF_ID, MODE_PRIVATE)
19 |
20 | fun getSketchNames(): LinkedList? {
21 | return prefs.getStringSet(NAMES_ID, null)?.let { LinkedList(it) }
22 | }
23 |
24 | fun saveSketch(name: String, sketch: Sketch?) {
25 | prefs.edit() {
26 |
27 | val oldNames = getSketchNames()
28 |
29 | if (oldNames != null) {
30 | this.putStringSet(
31 | NAMES_ID,
32 | LinkedHashSet(getSketchNames()).apply { add(name) })
33 |
34 | } else {
35 | this.putStringSet(NAMES_ID, LinkedHashSet().apply { add(name) })
36 | }
37 |
38 | sketch?.let {
39 | this.putString(name, sketch.toJsonString())
40 | return@edit
41 | }
42 | this.putString(name, null)
43 | }
44 | }
45 |
46 | fun deleteSketch(name: String) {
47 | prefs.edit(true) {
48 | putStringSet(NAMES_ID, LinkedHashSet(getSketchNames().apply { this!!.remove(name) }))
49 | putString(name, null)
50 | }
51 | Log.i("Names", "${getSketchNames()!!.contains(name)}" )
52 | }
53 |
54 |
55 | fun getSketch(name: String): Sketch? {
56 | return Sketch.fromJson(getSketchJson(name)).apply { this?.name = name }
57 | }
58 |
59 | private fun getSketchJson(name: String?): String? {
60 | return prefs.getString(name, null)
61 | }
62 |
63 |
64 | fun isValidName(name: String): Boolean {
65 | getSketchNames()?.let {
66 | if (it.contains(name) || name == NAMES_ID) {
67 | return false
68 | }
69 | }
70 | return true
71 | }
72 |
73 |
74 | }
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Game Of Life
3 | Settings
4 |
5 | First Fragment
6 | Second Fragment
7 | Next
8 | Previous
9 |
10 | Hello first fragment
11 | Hello second fragment. Arg: %1$s
12 | IntroActivity
13 | View Licenses
14 | Settings
15 | View Source on GitHub
16 | Select a ruleset
17 | Source
18 | Rules
19 | Change the rules of the game. This changes what will happen, when a cell has X neighbours. It can either die (default), live or be born
20 | Reset rules
21 | Browse rules
22 | Blueprints
23 | Create or use Blueprints to place predefined sections
24 | Create new Blueprint
25 | How should the Blueprint be named?
26 | Survive
27 | Born
28 | PLACE
29 | Guns
30 | A generic description
31 | Select a Blueprint
32 | Spaceships
33 | Oscillators
34 | Shipsynths
35 | Dimensions
36 | Name
37 | Bee Patterns
38 |
--------------------------------------------------------------------------------
/app/src/main/java/leko/valmx/thegameoflife/sheets/BlueprintSaveSheet.kt:
--------------------------------------------------------------------------------
1 | package leko.valmx.thegameoflife.sheets
2 |
3 | import android.content.Context
4 | import android.os.Bundle
5 | import android.text.Editable
6 | import android.text.TextWatcher
7 | import android.view.View
8 | import com.maxkeppeler.sheets.core.Sheet
9 | import kotlinx.android.synthetic.main.sheet_save_blueprint.*
10 | import leko.valmx.thegameoflife.R
11 | import leko.valmx.thegameoflife.game.tools.copypasta.Sketch
12 | import leko.valmx.thegameoflife.game.tools.copypasta.SketchLoadSaver
13 |
14 | class BlueprintSaveSheet(context: Context, val sketch: Sketch) : Sheet() {
15 |
16 | private var sketchName = ""
17 | private var sketchLoadSaver = SketchLoadSaver(context)
18 |
19 | fun show(ctx: Context) {
20 | this.windowContext = ctx
21 | this.width = null
22 |
23 | positiveText = "Save"
24 | positiveListener = {
25 |
26 | SketchLoadSaver(ctx).saveSketch(sketchName, sketch)
27 |
28 | }
29 | showsDialog = true
30 |
31 | this.show()
32 |
33 | }
34 |
35 | override fun onCreate(savedInstanceState: Bundle?) {
36 | super.onCreate(savedInstanceState)
37 | }
38 |
39 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
40 | super.onViewCreated(view, savedInstanceState)
41 | preview_blueprint.post {
42 | // preview_blueprint.previewManager.init(sketch)
43 | }
44 | displayButtonPositive(false)
45 |
46 | sheet_save_name_input.addTextChangedListener(object : TextWatcher {
47 | override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
48 |
49 | }
50 |
51 | override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
52 |
53 | if (s == null) return
54 |
55 | sketchName = s.toString().trim()
56 |
57 | displayButtonPositive(sketchName != "" && sketchLoadSaver.isValidName(sketchName))
58 |
59 | }
60 |
61 | override fun afterTextChanged(s: Editable?) {
62 |
63 | }
64 |
65 | })
66 | }
67 |
68 | override fun onCreateLayoutView(): View {
69 | return View.inflate(context, R.layout.sheet_save_blueprint, null)
70 | }
71 |
72 | }
--------------------------------------------------------------------------------
/app/src/main/java/leko/valmx/thegameoflife/utils/AssetUtils.kt:
--------------------------------------------------------------------------------
1 | package leko.valmx.thegameoflife.utils
2 |
3 | import android.content.Context
4 | import leko.valmx.thegameoflife.R
5 | import java.io.IOException
6 | import java.io.InputStream
7 | import java.nio.charset.Charset
8 |
9 | object AssetUtils {
10 |
11 | fun loadAssetString(context: Context, filename: String): String? {
12 | var json: String? = null
13 | json = try {
14 | val inputStream: InputStream = context.assets.open(filename)
15 | val size: Int = inputStream.available()
16 | val buffer = ByteArray(size)
17 | inputStream.read(buffer)
18 | inputStream.close()
19 | String(buffer, Charset.forName("UTF-8"))
20 | } catch (ex: IOException) {
21 | ex.printStackTrace()
22 | return null
23 | }
24 | return json
25 | }
26 |
27 | fun listAssetFiles(path: String, context: Context): Array {
28 | return try {
29 | context.assets.list(path) as Array
30 |
31 | } catch (e: IOException) {
32 | emptyArray()
33 | }
34 | }
35 |
36 | fun getPresetCategories(): Array {
37 | return arrayOf(
38 | PresetCategory(
39 | R.string.category_gliders,
40 | R.string.category_gliders_description,
41 | "guns", "https://conwaylife.com/wiki/Category:Guns"
42 | ),
43 | PresetCategory(
44 | R.string.spaceships,
45 | R.string.category_gliders_description,
46 | "spaceships", "https://conwaylife.com/wiki/Category:Guns"
47 | ),
48 | /*
49 | PresetCategory(
50 | R.string.shipsynths,
51 | R.string.category_gliders_description,
52 | "shipsynths", "https://conwaylife.com/wiki/Category:Guns"
53 | ),
54 | */
55 | PresetCategory(
56 | R.string.synths,
57 | R.string.category_gliders_description,
58 | "oscillators", "https://conwaylife.com/wiki/Category:Guns"
59 | ),
60 | PresetCategory(
61 | R.string.category_bee,
62 | R.string.category_gliders_description,
63 | "bee", "https://conwaylife.com/wiki/Category:Guns"
64 | )
65 | )
66 | }
67 |
68 | }
--------------------------------------------------------------------------------
/app/src/main/java/leko/valmx/thegameoflife/game/GridManager.kt:
--------------------------------------------------------------------------------
1 | package leko.valmx.thegameoflife.game
2 |
3 | import android.graphics.RectF
4 |
5 | class GridManager(val gameView: GameView) {
6 |
7 | var xOffset = 0F
8 | set(value) {
9 | if (value + gameView.width < 0) return
10 | if (value - gameView.width > cellWidth * Cells.mapSizeX) return
11 | field = value
12 | }
13 | var yOffset = 0F
14 | set(value) {
15 | if (value + gameView.height < 0) return
16 | if (value - gameView.height > cellWidth * Cells.mapSizeX) return
17 | field = value
18 | }
19 |
20 | var cellRadius = 0F
21 | var cellInset = 1F
22 |
23 | var defaultWidthCells = 40
24 |
25 | var cellWidth = 0F
26 | set(value) {
27 | field = value
28 | cellInset = cellWidth * .05F
29 | cellRadius = cellWidth * .08F
30 | }
31 |
32 | fun init() {
33 | cellWidth = (gameView.width / defaultWidthCells).toFloat()
34 |
35 | maxCellWidth = gameView.width / 1000F
36 | minCellWidth = gameView.width / 7F
37 | }
38 |
39 | fun getCellRect(x: Int, y: Int): RectF {
40 | return RectF(
41 | cellWidth * x - this.xOffset,
42 | cellWidth * y - this.yOffset,
43 | cellWidth * (x + 1) - this.xOffset,
44 | cellWidth * (y + 1) - this.yOffset
45 | )
46 | }
47 |
48 | private var maxCellWidth = gameView.width / 1000F
49 | private var minCellWidth = gameView.width / 7F
50 |
51 | fun zoom(
52 | zoomFactor: Float,
53 | focusX: Float = gameView.width / 2F,
54 | focusY: Float = gameView.height / 2f
55 | ) {
56 |
57 | if (validZoom(zoomFactor)) return
58 |
59 | var absX = this.xOffset / this.cellWidth
60 | var absY = this.yOffset / this.cellWidth
61 |
62 | absX -= (focusX / this.cellWidth) * (1 - zoomFactor)
63 | absY -= (focusY / this.cellWidth) * (1 - zoomFactor)
64 |
65 | this.cellWidth *= zoomFactor
66 |
67 | this.xOffset = absX * this.cellWidth
68 | this.yOffset = absY * this.cellWidth
69 | }
70 |
71 | private fun validZoom(zoomFactor: Float): Boolean {
72 | if (cellWidth >= minCellWidth && zoomFactor > 1) return true
73 | if (cellWidth <= maxCellWidth && zoomFactor < 1) return true
74 | return false
75 | }
76 |
77 |
78 | }
--------------------------------------------------------------------------------
/app/src/main/java/leko/valmx/thegameoflife/sheets/BlueprintSheet.kt:
--------------------------------------------------------------------------------
1 | package leko.valmx.thegameoflife.sheets
2 |
3 | import android.content.Context
4 | import android.os.Bundle
5 | import android.view.View
6 | import androidx.recyclerview.widget.LinearLayoutManager
7 | import com.maxkeppeler.sheets.core.Sheet
8 | import kotlinx.android.synthetic.main.sheet_rules.*
9 | import kotlinx.android.synthetic.main.sheet_stencil.*
10 | import leko.valmx.thegameoflife.R
11 | import leko.valmx.thegameoflife.game.GameView
12 | import leko.valmx.thegameoflife.game.tools.SelectionTool
13 | import leko.valmx.thegameoflife.game.tools.copypasta.Sketch
14 | import leko.valmx.thegameoflife.game.utils.GameRuleHelper
15 | import leko.valmx.thegameoflife.recyclers.RuleSheetAdapter
16 | import leko.valmx.thegameoflife.recyclers.SketchAdapter
17 |
18 | class BlueprintSheet(context: Context, val gameView: GameView) : Sheet(),
19 | SketchAdapter.OnSketchSelectedListener {
20 | fun show(ctx: Context) {
21 | this.windowContext = ctx
22 | this.width = null
23 |
24 | positiveText = "Apply"
25 | positiveListener = {
26 | val ruleSet = (rulesRecycler.adapter as RuleSheetAdapter).ruleSet
27 | GameRuleHelper(ctx).saveRule((rulesRecycler.adapter as RuleSheetAdapter).ruleSet)
28 | gameView.cells.ruleSet = ruleSet
29 | }
30 | showsDialog = true
31 | displayPositiveButton(false)
32 |
33 | this.show()
34 |
35 | }
36 |
37 | override fun onCreate(savedInstanceState: Bundle?) {
38 | super.onCreate(savedInstanceState)
39 |
40 | }
41 |
42 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
43 | super.onViewCreated(view, savedInstanceState)
44 |
45 | recycler2.layoutManager = LinearLayoutManager(context)
46 | recycler2.adapter = SketchAdapter(requireContext(), this)
47 |
48 | btn_new_blueprint.setOnClickListener {
49 | gameView.interactionManager.registeredInteraction = SelectionTool(gameView)
50 | dismiss()
51 | }
52 |
53 | btn_browse_preset_blueprints.setOnClickListener {
54 | BlueprintPresetSelectCategorySheet(requireContext(), gameView)
55 | }
56 |
57 | }
58 |
59 | override fun onCreateLayoutView(): View {
60 | return View.inflate(context, R.layout.sheet_stencil, null)
61 | }
62 |
63 | override fun onSketchSelected(sketch: Sketch) {
64 | // gameView.interactionManager.registeredInteraction = PasteTool(gameView, sketch)
65 | dismiss()
66 | }
67 | }
--------------------------------------------------------------------------------
/app/src/main/java/leko/valmx/thegameoflife/sheets/RulesSheet.kt:
--------------------------------------------------------------------------------
1 | package leko.valmx.thegameoflife.sheets
2 |
3 | import android.content.Context
4 | import android.os.Bundle
5 | import android.view.View
6 | import androidx.recyclerview.widget.LinearLayoutManager
7 | import com.maxkeppeler.sheets.core.Sheet
8 | import com.maxkeppeler.sheets.core.SheetStyle
9 | import kotlinx.android.synthetic.main.sheet_rules.*
10 | import leko.valmx.thegameoflife.R
11 | import leko.valmx.thegameoflife.game.GameView
12 | import leko.valmx.thegameoflife.game.utils.GameRuleHelper
13 | import leko.valmx.thegameoflife.recyclers.RulePresetPickerAdapter
14 | import leko.valmx.thegameoflife.recyclers.RuleSheetAdapter
15 |
16 | class RulesSheet(val gameView: GameView) : Sheet(),
17 | RulePresetPickerAdapter.RuleSelectedListener {
18 | fun show(ctx: Context) {
19 | this.windowContext = ctx
20 | style(SheetStyle.DIALOG)
21 | positiveText = "Apply"
22 | positiveListener = {
23 | val resultRuleSet = (rulesRecycler.adapter as RuleSheetAdapter).ruleSet
24 | GameRuleHelper(ctx).saveRule(resultRuleSet)
25 | gameView.cells.ruleSet = resultRuleSet
26 | }
27 |
28 | onNegative("BACK") {
29 | MoreOptionsSheet(requireContext(), gameView)
30 | }
31 | title(R.string.rules)
32 | this.show()
33 | }
34 |
35 | override fun onCreate(savedInstanceState: Bundle?) {
36 | super.onCreate(savedInstanceState)
37 | }
38 |
39 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
40 | super.onViewCreated(view, savedInstanceState)
41 | rulesRecycler.layoutManager = LinearLayoutManager(requireContext())
42 | updateUi(GameRuleHelper(requireContext()).apply { loadRules() }.ruleSet)
43 |
44 | btn_reset_rules.setOnClickListener {
45 | GameRuleHelper(requireContext()).resetRules()
46 | updateUi(GameRuleHelper(requireContext()).apply { loadRules() }.ruleSet)
47 | }
48 |
49 | btn_rule_presets.setOnClickListener {
50 | RulePresetSelectionSheet(requireContext(), gameView, this).show(requireContext())
51 | }
52 |
53 | }
54 |
55 | override fun onCreateLayoutView(): View {
56 | return View.inflate(context, R.layout.sheet_rules, null)
57 | }
58 |
59 | private fun updateUi(rule: GameRuleHelper.RuleSet) {
60 | rulesRecycler.adapter = RuleSheetAdapter(
61 | requireContext(), rule
62 | )
63 | }
64 |
65 | override fun onRuleSelected(rule: GameRuleHelper.RuleSet) {
66 | updateUi(rule)
67 | }
68 | }
--------------------------------------------------------------------------------
/app/src/main/java/leko/valmx/thegameoflife/recyclers/BlueprintPresetRecycler.kt:
--------------------------------------------------------------------------------
1 | package leko.valmx.thegameoflife.recyclers
2 |
3 | import android.util.Log
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import androidx.recyclerview.widget.RecyclerView.Adapter
8 | import androidx.recyclerview.widget.RecyclerView.ViewHolder
9 | import com.maxkeppeler.sheets.core.Sheet
10 | import kotlinx.android.synthetic.main.item_blueprint_selection.view.*
11 | import leko.valmx.thegameoflife.R
12 | import leko.valmx.thegameoflife.sheets.BlueprintInfoSheet
13 | import leko.valmx.thegameoflife.sheets.MoreOptionsSheet
14 | import leko.valmx.thegameoflife.utils.AssetUtils
15 | import leko.valmx.thegameoflife.utils.PresetCategory
16 | import leko.valmx.thegameoflife.utils.blueprints.Blueprint
17 |
18 | class BlueprintPresetRecycler(
19 | private val bluePrints: Array,
20 | private val category: PresetCategory,
21 | private val onBluePrintSelected: (Blueprint) -> Unit,
22 | private val originSheet: Sheet? = null
23 | ) :
24 | Adapter() {
25 |
26 | class VH(itemView: View) : ViewHolder(itemView) {
27 |
28 | }
29 |
30 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VH {
31 | return VH(
32 | LayoutInflater.from(parent.context)
33 | .inflate(R.layout.item_blueprint_selection, parent, false)
34 | )
35 | }
36 |
37 | override fun onBindViewHolder(holder: VH, position: Int) {
38 |
39 |
40 | val itemView = holder.itemView
41 | val blueprintName = bluePrints[position]
42 | Log.i("Loading Blueprint",blueprintName)
43 | val blueprint = Blueprint(
44 | AssetUtils.loadAssetString(
45 | itemView.context,
46 | "patterns/${category.path}/$blueprintName"
47 | )!!
48 | )
49 |
50 | itemView.blueprintName.text = blueprint.name
51 | itemView.blueprint_author.text = blueprint.author
52 |
53 |
54 | val preview = holder.itemView.preview
55 | preview.post {
56 |
57 | preview.init() {
58 | preview.previewManager.init(blueprint, true)
59 | }
60 | }
61 |
62 | itemView.setOnClickListener {
63 | BlueprintInfoSheet(blueprint).show(itemView.context)
64 | }
65 |
66 | itemView.btn_select_blueprint.setOnClickListener {
67 | onBluePrintSelected(blueprint)
68 | originSheet?.dismiss()
69 | }
70 |
71 |
72 | }
73 |
74 | override fun getItemCount(): Int = bluePrints.size
75 |
76 | }
--------------------------------------------------------------------------------
/app/src/main/java/leko/valmx/thegameoflife/recyclers/SketchAdapter.kt:
--------------------------------------------------------------------------------
1 | package leko.valmx.thegameoflife.recyclers
2 |
3 | import android.annotation.SuppressLint
4 | import android.content.Context
5 | import android.util.Log
6 | import android.view.LayoutInflater
7 | import android.view.View
8 | import android.view.ViewGroup
9 | import androidx.recyclerview.widget.RecyclerView
10 | import androidx.recyclerview.widget.RecyclerView.Adapter
11 | import kotlinx.android.synthetic.main.item_saved_sketch.view.*
12 | import leko.valmx.thegameoflife.R
13 | import leko.valmx.thegameoflife.game.tools.copypasta.Sketch
14 | import leko.valmx.thegameoflife.game.tools.copypasta.SketchLoadSaver
15 |
16 | class SketchAdapter(context: Context, val onSketchSelectedListener: OnSketchSelectedListener) :
17 | Adapter() {
18 |
19 | val sketchManager = SketchLoadSaver(context)
20 |
21 | var names = sketchManager.getSketchNames()
22 |
23 | inner class VH(item: View) : RecyclerView.ViewHolder(item) {
24 |
25 | @SuppressLint("NotifyDataSetChanged")
26 | fun bind(name: String, sketchLoadSaver: SketchLoadSaver) {
27 | val sketch = sketchLoadSaver.getSketch(name)
28 | itemView.gameView.post {
29 | itemView.gameView.init() {
30 | try {
31 |
32 | // itemView.gameView.previewManager.init(sketch!!, true)
33 | } catch (ignored: java.lang.Exception) {
34 |
35 | }
36 | }
37 | }
38 |
39 | itemView.place_btn.setOnClickListener {
40 | onSketchSelectedListener.onSketchSelected(sketch!!)
41 | }
42 |
43 | itemView.sketch_name.text = name
44 |
45 | itemView.btn_delete_sketch.setOnClickListener {
46 | sketchLoadSaver.deleteSketch(name)
47 | names = sketchManager.getSketchNames()
48 | notifyDataSetChanged()
49 | }
50 |
51 | }
52 |
53 | }
54 |
55 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VH {
56 | return VH(
57 | LayoutInflater.from(parent.context).inflate(R.layout.item_saved_sketch, parent, false)
58 | )
59 | }
60 |
61 | override fun onBindViewHolder(holder: VH, position: Int) {
62 | holder.bind(names!![position], sketchManager)
63 | }
64 |
65 | override fun getItemCount(): Int {
66 |
67 | Log.i("NAMES ARE", "${names?.size}")
68 |
69 | return names?.size ?: 0
70 | }
71 |
72 | interface OnSketchSelectedListener {
73 | fun onSketchSelected(sketch: Sketch)
74 | }
75 |
76 | }
--------------------------------------------------------------------------------
/app/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
31 |
32 |
36 |
37 |
42 |
43 |
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/app/src/main/java/leko/valmx/thegameoflife/IntroActivity.kt:
--------------------------------------------------------------------------------
1 | package leko.valmx.thegameoflife
2 |
3 | import android.content.Intent
4 | import android.os.Bundle
5 | import android.os.Handler
6 | import android.os.PersistableBundle
7 | import android.util.Log
8 | import androidx.appcompat.app.AppCompatActivity
9 | import kotlinx.android.synthetic.main.activity_intro.*
10 | import leko.valmx.thegameoflife.game.tools.copypasta.SketchLoadSaver
11 | import leko.valmx.thegameoflife.utils.AssetUtils
12 | import leko.valmx.thegameoflife.utils.blueprints.Blueprint
13 |
14 | class IntroActivity : AppCompatActivity() {
15 |
16 | override fun onCreate(savedInstanceState: Bundle?) {
17 | super.onCreate(savedInstanceState)
18 | setContentView(R.layout.activity_intro)
19 |
20 | }
21 |
22 | override fun onPostCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
23 | super.onPostCreate(savedInstanceState, persistentState)
24 | // preview.init()
25 | }
26 |
27 | override fun onPostCreate(savedInstanceState: Bundle?) {
28 | super.onPostCreate(savedInstanceState)
29 | preview.post {
30 |
31 |
32 | val loader = SketchLoadSaver(this)
33 | val r = java.util.Random()
34 |
35 | val category = "preview"
36 |
37 |
38 | val names =
39 | AssetUtils.listAssetFiles("patterns/${category}", this)
40 | val pickedId = r.nextInt(names.size)
41 |
42 | val patternName =
43 |
44 | names[pickedId]
45 | Log.d(
46 | "Path of intro shape", "patterns/${category}/$patternName"
47 | )
48 | Log.d(
49 | "Size of shape pool", names.size.toString()
50 | )
51 | val blueprint = Blueprint(
52 | AssetUtils.loadAssetString(
53 | this,
54 | "patterns/${category}/$patternName"
55 | )!!
56 | )
57 | preview.init() {
58 | preview.previewManager.init(blueprint)
59 | }
60 | // preview.actorManager.ruleSet = GameRuleHelper.RuleSet(0b000011000000100)
61 |
62 |
63 | }
64 |
65 | Handler().postDelayed(object : Runnable {
66 |
67 | var counter = 0
68 |
69 | override fun run() {
70 |
71 | counter++;
72 | // preview.actorManager.aLength = (300/counter).toLong()
73 |
74 | if (counter >= 100) {
75 | preview.animationManager.running = false
76 | startActivity(Intent(this@IntroActivity, MainActivity::class.java))
77 | return
78 | }
79 |
80 | // preview.actorManager.doCycle()
81 |
82 | Handler().postDelayed(this, (300/counter).toLong())
83 | }
84 |
85 |
86 | }, 0L)
87 |
88 | }
89 |
90 |
91 | }
--------------------------------------------------------------------------------
/app/src/main/java/leko/valmx/thegameoflife/sheets/MoreOptionsSheet.kt:
--------------------------------------------------------------------------------
1 | package leko.valmx.thegameoflife.sheets
2 |
3 | import android.content.ActivityNotFoundException
4 | import android.content.Context
5 | import android.content.Intent
6 | import android.net.Uri
7 | import androidx.core.content.ContextCompat
8 | import com.maxkeppeler.sheets.core.SheetStyle
9 | import com.maxkeppeler.sheets.option.Option
10 | import com.maxkeppeler.sheets.option.OptionSheet
11 | import leko.valmx.thegameoflife.R
12 | import leko.valmx.thegameoflife.SettingActivity
13 | import leko.valmx.thegameoflife.game.GameView
14 | import leko.valmx.thegameoflife.game.tools.SelectionTool
15 |
16 |
17 | class MoreOptionsSheet(context: Context, gameView: GameView) {
18 | init {
19 | OptionSheet().show(context) {
20 |
21 | title("Select an Option")
22 | columns(3)
23 | // withInfo(Info("S"))
24 | style(SheetStyle.DIALOG)
25 | with(
26 | Option(R.drawable.ic_round_ballot_24, "Change rules"),
27 | Option(R.drawable.upload, "Place Blueprint"),
28 | Option(R.drawable.settings, "App Settings"),
29 | Option(R.drawable.ic_round_photo_size_select_small_24, "Start Selection"),
30 | Option(R.drawable.trash_2, "Clear everything"),
31 | Option(R.drawable.star, "Rate")
32 | )
33 | onPositive { index: Int, option: Option ->
34 |
35 | if (index == 0) RulesSheet(gameView).show(context)
36 | if (index == 1) BlueprintPresetSelectCategorySheet(context, gameView)
37 | if (index == 2) startActivity(Intent(context, SettingActivity::class.java))
38 | if (index == 3) gameView.interactionManager.registeredInteraction =
39 | SelectionTool(gameView)
40 | if (index == 4) gameView.cells.clearCells()
41 | if (index == 5) {
42 |
43 | val appPackageName: String =
44 | "leko.valmx.thegameoflife" // package name of the app
45 |
46 | try {
47 | ContextCompat.startActivity(
48 | context,
49 | Intent(
50 | Intent.ACTION_VIEW,
51 | Uri.parse("market://details?id=$appPackageName")
52 | ), null
53 | )
54 | } catch (anfe: ActivityNotFoundException) {
55 | ContextCompat.startActivity(
56 | context,
57 | Intent(
58 | Intent.ACTION_VIEW,
59 | Uri.parse("https://play.google.com/store/apps/details?id=$appPackageName")
60 | ), null)
61 |
62 | }
63 | }
64 | }
65 |
66 | }
67 |
68 | }
69 | }
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_saved_sketch.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
16 |
17 |
29 |
30 |
39 |
40 |
49 |
50 |
67 |
68 |
--------------------------------------------------------------------------------
/app/src/main/java/leko/valmx/thegameoflife/utils/blueprints/Blueprint.kt:
--------------------------------------------------------------------------------
1 | package leko.valmx.thegameoflife.utils.blueprints
2 |
3 | import android.util.Log
4 | import java.util.LinkedList
5 |
6 | class Blueprint(rleString: String) {
7 |
8 | val iterator = LinkedList(rleString.split("\n")).iterator()
9 | val comments: LinkedList = LinkedList()
10 | var author = ""
11 | var name = ""
12 |
13 | private var nextLine = iterator.next()
14 |
15 | init {
16 |
17 |
18 | while (iterator.hasNext() && nextLine.startsWith("#")) {
19 |
20 | when {
21 |
22 | nextLine.startsWith("#O ") -> {
23 | author = nextLine.drop(3)
24 | }
25 |
26 | nextLine.startsWith("#N ") -> {
27 | name = nextLine.drop(3).replace(".rle", "")
28 | }
29 |
30 |
31 | nextLine.startsWith("#C ") -> {
32 | comments.add(nextLine.drop(3))
33 | }
34 |
35 | }
36 |
37 | nextLine = iterator.next()
38 | }
39 |
40 | }
41 |
42 | var width: Int
43 | var height: Int
44 | var rule = "3/23"
45 |
46 | init {
47 | nextLine = nextLine.replace(" ", "")
48 |
49 | val params = nextLine.split(",")
50 |
51 | width = params[0].removePrefix("x=").toInt()
52 | height = params[1].removePrefix("y=").toInt()
53 |
54 | if (params.size == 3) rule = params[2].removePrefix("r=")
55 | }
56 |
57 | var cells = Array(width) { Array(height) { false } }
58 | set(value) {
59 | field = value
60 | height = cells[0].size
61 | width = cells.size
62 | }
63 |
64 | init {
65 | var cellString = ""
66 |
67 | while (iterator.hasNext()) cellString += iterator.next()
68 |
69 | // How much will one feature be repeated
70 | var digitString = ""
71 |
72 | var rowIndex = 0
73 | var lineIndex = 0
74 |
75 | Log.i("RLE", rleString)
76 |
77 | var stop = false
78 |
79 | cellString.toCharArray().forEach { char ->
80 |
81 | if (char == '!') {
82 | stop = true
83 | }
84 |
85 | if (stop) return@forEach
86 |
87 | if (!char.isDigit() && !arrayOf('o', 'b', '$').contains(char)) return@forEach
88 |
89 | if (char.isDigit()) {
90 | digitString += char
91 | } else {
92 |
93 | val repeatAmount = if (digitString != "") {
94 | digitString.toInt()
95 | } else {
96 | 1
97 | }
98 |
99 | repeat(repeatAmount) {
100 |
101 | if (rowIndex >= width) {
102 | rowIndex = 0
103 | }
104 |
105 | if (char == '$') {
106 | lineIndex++;
107 | rowIndex = 0
108 | return@repeat
109 | }
110 |
111 | cells[rowIndex][lineIndex] = char == 'o'
112 |
113 | rowIndex++
114 | }
115 | digitString = ""
116 | }
117 | }
118 | }
119 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/sheet_source.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
17 |
18 |
26 |
27 |
36 |
37 |
38 |
46 |
47 |
55 |
56 |
65 |
66 |
67 |
75 |
76 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_preset_extra_info.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
17 |
18 |
26 |
27 |
36 |
37 |
38 |
46 |
47 |
55 |
56 |
65 |
66 |
67 |
75 |
76 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/sheet_stencil.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
17 |
18 |
28 |
29 |
38 |
39 |
56 |
57 |
74 |
75 |
84 |
85 |
--------------------------------------------------------------------------------
/app/src/main/java/leko/valmx/thegameoflife/recyclers/ThemeAdapter.kt:
--------------------------------------------------------------------------------
1 | package leko.valmx.thegameoflife.recyclers
2 |
3 | import android.view.LayoutInflater
4 | import android.view.View
5 | import android.view.ViewGroup
6 | import androidx.recyclerview.widget.RecyclerView.Adapter
7 | import androidx.recyclerview.widget.RecyclerView.ViewHolder
8 | import kotlinx.android.synthetic.main.activity_main.view.*
9 | import leko.valmx.thegameoflife.MainActivity
10 | import leko.valmx.thegameoflife.R
11 | import leko.valmx.thegameoflife.game.GameView
12 | import java.util.*
13 |
14 | class ThemeAdapter(val game: GameView, val mainActivity: MainActivity) :
15 | Adapter() {
16 |
17 | class ThemeBundle(
18 | val back: Int,
19 | val cell: Int,
20 | val grid: Int,
21 | val ui: Int,
22 | val icon: Int,
23 | val tool: Int,
24 | val toolStroke: Int
25 | )
26 |
27 | val themes = LinkedList()
28 |
29 | init {
30 |
31 | val res = game.resources
32 |
33 | themes.add(
34 | ThemeBundle(
35 | res.getColor(R.color.back_1),
36 | res.getColor(R.color.back_secondary_1),
37 | res.getColor(R.color.cell_1),
38 | res.getColor(R.color.grid_1),
39 | res.getColor(R.color.ui_1),
40 | res.getColor(R.color.icon_1),
41 | res.getColor(R.color.tool_1),
42 | )
43 | )
44 | /* themes.add(
45 | ThemeBundle(
46 | res.getColor(R.color.back_2),
47 | res.getColor(R.color.cell_2),
48 | res.getColor(R.color.grid_2),
49 | res.getColor(R.color.ui_2),
50 | res.getColor(R.color.icon_2),
51 | res.getColor(R.color.tool_1),
52 | res.getColor(R.color.tool_stroke_1),
53 | )
54 | )*/
55 | themes.add(
56 | ThemeBundle(
57 | res.getColor(R.color.back_3),
58 | res.getColor(R.color.back_secondary_3),
59 | res.getColor(R.color.cell_3),
60 | res.getColor(R.color.grid_3),
61 | res.getColor(R.color.ui_3),
62 | res.getColor(R.color.icon_3),
63 | res.getColor(R.color.tool_3),
64 | )
65 | )
66 | /* themes.add(
67 | ThemeBundle(
68 | res.getColor(R.color.back_4),
69 | res.getColor(R.color.cell_4),
70 | res.getColor(R.color.grid_4),
71 | res.getColor(R.color.ui_4),
72 | res.getColor(R.color.icon_4),
73 | res.getColor(R.color.tool_1),
74 | res.getColor(R.color.tool_stroke_1),
75 | )
76 | )*/
77 | }
78 |
79 |
80 | class VH(itemView: View) : ViewHolder(itemView)
81 |
82 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VH = VH(
83 | LayoutInflater.from(parent.context).inflate(
84 | R.layout.item_theme_picker, parent, false
85 | )
86 | )
87 |
88 | override fun onBindViewHolder(holder: VH, position: Int) {
89 | val themeBundle = themes[position]
90 | val itemView = holder.itemView
91 |
92 | itemView.themeView.backColor.color = themeBundle.back
93 | itemView.themeView.cellColor.color = themeBundle.cell
94 | itemView.themeView.gridColor.color = themeBundle.grid
95 |
96 | itemView.setOnClickListener {
97 | game.gameColors.applyTheme(themeBundle, mainActivity)
98 | mainActivity.onThemeSelected(themeBundle)
99 | }
100 |
101 | }
102 |
103 | override fun getItemCount(): Int = themes.size
104 |
105 | }
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | xmlns:android
18 |
19 | ^$
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | xmlns:.*
29 |
30 | ^$
31 |
32 |
33 | BY_NAME
34 |
35 |
36 |
37 |
38 |
39 |
40 | .*:id
41 |
42 | http://schemas.android.com/apk/res/android
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 | .*:name
52 |
53 | http://schemas.android.com/apk/res/android
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 | name
63 |
64 | ^$
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 | style
74 |
75 | ^$
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 | .*
85 |
86 | ^$
87 |
88 |
89 | BY_NAME
90 |
91 |
92 |
93 |
94 |
95 |
96 | .*
97 |
98 | http://schemas.android.com/apk/res/android
99 |
100 |
101 | ANDROID_ATTRIBUTE_ORDER
102 |
103 |
104 |
105 |
106 |
107 |
108 | .*
109 |
110 | .*
111 |
112 |
113 | BY_NAME
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
--------------------------------------------------------------------------------
/app/src/main/java/leko/valmx/thegameoflife/sheets/BlueprintPresetSelectionSheet.kt:
--------------------------------------------------------------------------------
1 | package leko.valmx.thegameoflife.sheets
2 |
3 | import android.content.Context
4 | import android.os.Bundle
5 | import android.util.Log
6 | import android.view.View
7 | import androidx.recyclerview.widget.GridLayoutManager
8 | import com.maxkeppeler.sheets.core.IconButton
9 | import com.maxkeppeler.sheets.core.Sheet
10 | import com.maxkeppeler.sheets.core.SheetStyle
11 | import com.maxkeppeler.sheets.info.InfoSheet
12 | import kotlinx.android.synthetic.main.sheet_predefined_selector.*
13 | import leko.valmx.thegameoflife.R
14 | import leko.valmx.thegameoflife.game.GameView
15 | import leko.valmx.thegameoflife.game.tools.PasteTool
16 | import leko.valmx.thegameoflife.game.utils.GameRuleHelper
17 | import leko.valmx.thegameoflife.recyclers.BlueprintPresetRecycler
18 | import leko.valmx.thegameoflife.utils.AssetUtils
19 | import leko.valmx.thegameoflife.utils.PresetCategory
20 | import leko.valmx.thegameoflife.utils.blueprints.Blueprint
21 | import java.util.*
22 |
23 | class BlueprintPresetSelectionSheet(
24 | private val gameView: GameView,
25 | private val category: PresetCategory
26 | ) : Sheet() {
27 |
28 | private lateinit var data: Array
29 |
30 |
31 | init {
32 | show(gameView.context)
33 | }
34 |
35 | fun show(ctx: Context) {
36 | this.windowContext = ctx
37 | this.width = null
38 | style(SheetStyle.DIALOG)
39 |
40 |
41 | this.show()
42 | onNegative("Back") {
43 | BlueprintPresetSelectCategorySheet(gameView.context, gameView)
44 | }
45 | positiveText = "Cancel"
46 |
47 | title("Select one item...")
48 |
49 | displayToolbar()
50 | withIconButton(IconButton(R.drawable.external_link)) {
51 | SourceSheet(
52 | requireContext(),
53 | category.url,
54 | "16.12.2022",
55 | "GNU Free Documentation License 1.2",
56 | "https://www.gnu.org/licenses/fdl-1.3.html"
57 | )
58 | }
59 |
60 | }
61 |
62 | override fun dismiss() {
63 | super.dismiss()
64 | System.gc()
65 | }
66 |
67 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
68 | super.onViewCreated(view, savedInstanceState)
69 |
70 |
71 |
72 | data = AssetUtils.listAssetFiles("patterns/${category.path}", requireContext())
73 | Arrays.sort(data)
74 | Log.d("Loaded assets", data.contentToString())
75 |
76 | presets_recycler.layoutManager = GridLayoutManager(context, 2)
77 | presets_recycler.adapter =
78 | BlueprintPresetRecycler(data, category, {
79 |
80 | val newRule = GameRuleHelper.RuleSet(it.rule)
81 | val gameRuleHelper = GameRuleHelper(requireContext()).apply { loadRules() }
82 |
83 | val initPasteTool = {
84 | gameView.interactionManager.registeredInteraction =
85 | PasteTool(gameView, it)
86 |
87 | }
88 |
89 | if (gameRuleHelper.ruleSet.getRuleInt() != newRule.getRuleInt()) {
90 | InfoSheet().show(requireContext()) {
91 | showsDialog = true
92 | title("This pattern needs a different rule set to work")
93 | content("Change the rule to ${it.rule}?")
94 | onPositive("Yes") {
95 | gameRuleHelper.saveRule(newRule)
96 | gameView.cells.ruleSet = newRule
97 | initPasteTool()
98 | }
99 |
100 | onNegative(initPasteTool)
101 |
102 | }
103 | return@BlueprintPresetRecycler
104 | }
105 | initPasteTool()
106 |
107 | }, this)
108 |
109 | }
110 |
111 | private fun loadAllBlueprints(): Array {
112 |
113 | val result = LinkedList()
114 |
115 | val assetFiles = AssetUtils.listAssetFiles("patterns/ship", requireContext())
116 |
117 | return assetFiles
118 | }
119 |
120 | override fun onCreateLayoutView(): View {
121 | return View.inflate(context, R.layout.sheet_predefined_selector, null)
122 | }
123 |
124 |
125 | }
--------------------------------------------------------------------------------
/app/src/main/java/leko/valmx/thegameoflife/game/utils/GameRuleHelper.kt:
--------------------------------------------------------------------------------
1 | package leko.valmx.thegameoflife.game.utils
2 |
3 | import android.content.Context
4 | import android.content.Context.MODE_PRIVATE
5 | import leko.valmx.thegameoflife.utils.AssetUtils
6 | import java.util.*
7 | import kotlin.math.pow
8 |
9 | class GameRuleHelper(val ctx: Context) {
10 | val PREF_ID = "CWGOL_VAL_RULES"
11 | val SAVE_ID = "RULE"
12 |
13 |
14 | lateinit var ruleSet: RuleSet
15 |
16 | private val defaultRuleInt = 0b000011000000100
17 |
18 | val defaultRuleSet =
19 | RuleSet(defaultRuleInt)
20 |
21 | fun resetRules() {
22 | saveRule(defaultRuleSet)
23 | }
24 |
25 | val prefs = ctx.getSharedPreferences(PREF_ID, MODE_PRIVATE)
26 |
27 | fun loadRules() {
28 |
29 | ruleSet = RuleSet(prefs.getInt(SAVE_ID, defaultRuleInt))
30 | }
31 |
32 | fun loadPresetRules(): HashMap {
33 | val rules =
34 | AssetUtils.loadAssetString(ctx, "rules/rules.txt")!!.replace("\n", "").split("//")
35 |
36 | val result = HashMap()
37 |
38 | rules.forEach { rule ->
39 |
40 | val name = rule.substringAfter("$")
41 | val ruleString = rule.substringBefore("$")
42 |
43 | result[name] = ruleString
44 | }
45 |
46 | return result
47 |
48 | }
49 |
50 | fun saveRule(rule: RuleSet) {
51 | val edit = prefs.edit()
52 |
53 | edit.putInt(SAVE_ID, rule.getRuleInt())
54 | edit.apply()
55 | }
56 |
57 | class RuleSet {
58 | private val bornValues: Array = Array(8) { false }
59 | private val surviveValues: Array = Array(8) { false }
60 | private val defaultRuleInt = 0b000011000000100
61 |
62 |
63 | constructor(ruleInt: Int) {
64 | initWithRuleInt(ruleInt)
65 | }
66 |
67 | constructor(input: String) {
68 | try {
69 | val ruleString = input.replace("rule=", "")
70 | var result = 0
71 |
72 | val rules = ruleString.split("/")
73 | val bornRules = rules[0].toLowerCase(Locale.ROOT).strip().substringAfter("b")
74 | val surivalRules = rules[1].toLowerCase(Locale.ROOT).strip().substringAfter("s")
75 |
76 |
77 | bornRules.toCharArray().forEach {
78 | result += (2.0.pow(it.digitToInt().toDouble() - 1)).toInt()
79 | }
80 | surivalRules.toCharArray().forEach {
81 | result += (2.0.pow(8 + it.digitToInt().toDouble() - 1)).toInt()
82 |
83 | }
84 | initWithRuleInt(result)
85 | } catch (e: Exception) {
86 | initWithRuleInt(defaultRuleInt)
87 | }
88 | }
89 |
90 | private fun initWithRuleInt(ruleInt: Int) {
91 |
92 | var lastInt = ruleInt
93 | var i = 0
94 | while (lastInt != 0 && i != 16) {
95 |
96 | if (lastInt % 2 == 1) {
97 | if (i >= 8) {
98 | surviveValues[i - 8] = true
99 |
100 | } else {
101 | bornValues[i] = true
102 | }
103 | }
104 | lastInt /= 2
105 |
106 | i++;
107 | }
108 |
109 |
110 | }
111 |
112 | fun willBeBorn(neighbours: Int): Boolean {
113 | if (neighbours == 0 || neighbours>=8) return false
114 |
115 | return bornValues[neighbours - 1]
116 | }
117 |
118 | fun willSurvive(neighbours: Int): Boolean {
119 | if (neighbours == 0) return false
120 | return surviveValues[neighbours - 1]
121 | }
122 |
123 | fun setBorn(neighbours: Int, bool: Boolean) {
124 | bornValues[neighbours] = bool
125 | }
126 |
127 | fun setSurvive(neighbours: Int, bool: Boolean) {
128 | surviveValues[neighbours] = bool
129 | }
130 |
131 | fun getRuleInt(): Int {
132 | var res = 0;
133 | bornValues.forEachIndexed { index, b ->
134 | if (b) res += 2.0.pow(index).toInt();
135 | }
136 |
137 | surviveValues.forEachIndexed { index, b ->
138 | if (b) res += 2.0.pow(index + 8).toInt();
139 | }
140 | return res
141 |
142 | }
143 |
144 | }
145 |
146 |
147 | }
--------------------------------------------------------------------------------
/app/src/main/assets/patterns/guns/quetzal54.rle:
--------------------------------------------------------------------------------
1 | #C https://conwaylife.com/wiki/Quetzal
2 | #C https://www.conwaylife.com/patterns/quetzal54.rle
3 | #N Period-54 Quetzal
4 | #C Phil's Game of Life Viewer
5 | #C https://GOLHobby.com/life.htm?pattern=n1230
6 | x = 269, y = 267, rule = B3/S23
7 | 165bo$151b2o10b3o$150bo2bo8bo$149bobobo8b2o$149bobob2o$147b2obo3bo5bo
8 | $147bo2bob3o4bobo$144b2obobobo2bo5b2o2b2o$144bo2bo5b2o9b2o$145b2o4bob
9 | o$147b5obo$147bo4bo$148b4o$149bo$147bo8bo$147b2o5b2o$155b2o$168b2o$
10 | 168bobo$168bo$12b$27b$27b$25b$25b$27b$27b$26b$141bobo$141b2o$142bo$
11 | 181b3o$107b2o72bo$107bo2b2o70bo$105bobo3bo$104bobob3o$104bo3bo$101b2o
12 | bo3bob3o$89b2o10b2obobobobo2bo$90bo13bobob2o2b2o$90bobo11b2o$91b2o2b
13 | 2o32bo$95b2o30b2o$74b2o4b2o46b2o$74bobo4bo24bo88b2o$77bo3bob2o21b3o
14 | 86bobo$75b2obob2obobo20bobo86bo$74bo3bobo2bobo22bo$75bo2bo2bo3b2o$75b
15 | o2b2o3b2o3bo6bo$69b2o6b3o3bobo8bob2o25b3o$69bo2bobo2b3o5bo3bo4bob2o
16 | 25bo$70b4o3bo4bo8bo32bo$73bo9b3o3bobo$70b2o9bobo4bo18b2o$70bo8b3obob
17 | 2o20bobo$71bo6bo4bobo8bob2o11bo10b2o$70b2o6b2o3bobo8bo2bo11b2o9bobo$
18 | 84bo9b3o23bo87b3o$101b2o105bo$101bobo105bo$103bo2b2o$98bo3b2obobo$83b
19 | 2o12bo3bo3bo31b2o$84bo12bo3b5o2bo28bobo$84bobo19b3o28bo$85b2o14b3obo$
20 | 100bo5bo$88b3o9b6o$88bo$92bo9b4o3bo23b3o$89bo2bo9bo3bobobo22bo88b2o$
21 | 90b2o13b2obobo23bo87bobo$107bobob2o109bo$92bo9b2o2b2obo2bo$89bo4bo13b
22 | obobob2o$90bo2bo11b2obob3o2bo$90b3o13bo2bo3b2o35b3o$86b2o18bob5o37bo$
23 | 86b2o19bo4bo38bo$108b4o$110bo$112bo$111b2o34b2o$80b2o23bo41bobo$79bob
24 | o24bo40bo87b3o$75b2o2bo8bo15b3o128bo$75bobob2o8bo146bo$77bo3bo4bob3o
25 | 7b2o$74bo2bobob2o2b2o2b2o7bo$74b3o2bobo3b2o2b2o5bobo65b2o$77b2obo15b
26 | 2o66bobo93b2o$76bo2bo2bo6b2o73bo94bobo$77b6o2bo4bo168bo$85bo4bo162b2o
27 | 2b2ob4o$73bo3b4o6bobo163bo2bobobo2bo$72bobobo3bo174b2ob2o4b2o$72bobob
28 | 2o82b3o93bobob4o2bo$70b2obo3bo41bo40bo88b2o5bob2obo2b2obo$70bo2bob2o
29 | 40bobo41bo87bobo5bo4bo4bo$67b2obobobo2bo40b2o129bo8b3o3b3o$67bo2bobob
30 | ob2o182bobobo$68b2o6bo184b3o$70b5obo19bo98b2o$70bo4bo6bobo10b2o80b3o
31 | 14bobo$71b4o7b2o10b3o80bo16bo$72bo10bo10bo83bo9b2o2b2ob4o63bo$70bo21b
32 | o95bo2bobobo2bo62bobo$70b2o20bo3b2o92b2o4bo2b2o60b2o$96b2o3b2o88bob2o
33 | 2b2o2bo63b2o$93bo7bobo70b2o15bobob2o2b2obo62bobo$94bo2bo5bo2b2o24bo
34 | 41bobo15bo5bo3bo50bo6b2o5bo$94b3o5b2obobo25bo40bo18b3obob3o51b2o5b2o
35 | 5b2o$83b2o20bo25b3o61bobobo52bobo$84bo16b5o2bo$84bobo15bo3b3o87b3o$
36 | 85b2o14b2ob2o$70bo29bo5bo84b2o$68b2o30b6o85bobo3b2o$69b2o120bo4bo$
37 | 102b4o3bo86b2o$102bo3bobobo89b2o$105b2obobo89bobo$105bo3bob2o82b2o5bo
38 | $93b2o10b3obo2bo74b3o5b2o5b2o5b2o$95b2o8bo2bobobob2o30bo40bo21bobo27b
39 | 2o$89b2o5bo8b2o5bo2bo28bobo41bo22bo28b2o$88bo7bo9bobo4b2o30b2o60b4ob
40 | 2o2b2o21bo$88bo6bo10bob5o94bo2bobobo2bo$88bo3b2o13bo4bo92b2o4b2ob2o$
41 | 108b4o69bo22bo2b4obobo$55bobo52bo70b2o20bob2o2bob2obo$55b2o55bo67bobo
42 | 20bo4bo4bo$56bo54b2o91b3o3b3o$80b2o124bobobo$79bobo125b3o$75b2o2bo27b
43 | o$75bobob2o27bo92b2o$77bo3bo7bo8b2o6b3o50bo41bobo22bo$74bo2b5o7bo8bo
44 | 61bo40bo6bo17b2o$74b3o2bobo6bo7bobo59b3o46bobo15bobo$77bo11b2o5b2o
45 | 109b2o$76bo2bo2bo6b4o118b2o$77b6o7bo2bo117bobo$43bo46bo2bo73b2o37b2o
46 | 5bo$41b2o30bo3b4o9b3o75b2o36b2o5b2o$42b2o28bobobo3bo86bo$72bobob2o$
47 | 70b2obo4bo$70bo2bobob2o$67b2obo2b2o3bo42bo71bo$67bo2b2obo2b2o41bobo
48 | 71b2o$68b2o2bobobo43b2o51bo18bobo17b2o$70b5obo18b2o74bobo39b2o$70bo4b
49 | o19b2o75b2o38bo$71b4o$72bo7bobo$70bo9b2o72bo$28bobo39b2o9bo72b2o$28b
50 | 2o123bobo$29bo64bob2o$93b5o$93b4o$134bo$94b3o38bo43b2o$94b3o36b3o44b
51 | 2o4bo12bo$95bo83bo7bo11b2o$89bo95b3o10bobo$88bobo114b2o$68bo20bo116bo
52 | $66b2o136bo$16bo50b2o71b2o60b4o$14b2o125b2o58bo4bo$2o5b2o6b2o123bo59b
53 | ob5o$bo5b2o191bobo4b2o$bobo184b2o9b2o5bo2bo$2b2o43b2o5b2o132b2o2b2o5b
54 | o2bobobob2o$6b2o40bo5b2o92bo17bo25bobo4b3obo2bo$5bobo40bobo95bobo17b
55 | 2o25bo5bo3bob2o$6bo42b2o96b2o16bobo31b2obobo$53b2o135b2o8bobobo$52bob
56 | o136bo8bo2bo$53bo6bo127b3o10b2o$61bo126bo$4b2ob2o9bo40b3o65bo$2b3obob
57 | 3o8bo32b3o72b2o$bo4bo4bo5b3o106bobo$bob2o2b2obobo38bobobo$2bo2b2o3bob
58 | o36b3obob3o$3b2o2b2obob2o34bo3bo5bo$5bo4bobo2bo32bob2o2b2obobo101bo$
59 | 5b4ob2o2b2o33bo2b2o2b2obo92b2o8bo$9bo40b2o2bo4b2o92b2o5b3o$7bobo42bo
60 | 2bobobo2bo89bo$7b2o43b4ob2o2b2o$56bo$54bobo17bo$54b2o16bobo$32bo40b2o
61 | 38b2o$30bobo81b2o$31b2o80bo4$139bo35bo$139b2o32bobo$138bobo33b2o3$87b
62 | o$88bo$45bo40b3o11bo$46bo53b2o$44b3o52bobo5b2o$108bo$106bo$104b4o$
63 | 103bo4bo$102bobobobo16b2o$102bobo4b2o15b2o$90b2o9b2o4b2o2bo13bo$90b2o
64 | 2b2o4bo2bobo2bob2o$94bobo2b3o3bo2bo$95bo4bo2bobob2o$101b2obobo$59bo
65 | 32b2o8bobobo$57bobo33bo8bo2bo$58b2o30b3o10b2o$90bo3$112bo$112b2o$111b
66 | obo5$72bo$73bo$71b3o5$98b2o$99b2o$98bo4$101b2o$86bo15bo$84bobo13bo$
67 | 85b2o11b4o$97bo4bo$96bobobobo$96bobo4b2o$84b2o9b2o4b2o2bo$84b2o2b2o4b
68 | o2bobo2bob2o$88bobo2b3o3bo2bo$89bo4bo2bobob2o$95b2obobo$86b2o8bobobo$
69 | 87bo8bo2bo$84b3o10b2o$84bo!
--------------------------------------------------------------------------------
/app/src/main/java/leko/valmx/thegameoflife/game/GameColors.kt:
--------------------------------------------------------------------------------
1 | package leko.valmx.thegameoflife.game
2 |
3 | import android.annotation.SuppressLint
4 | import android.content.Context
5 | import android.content.Context.MODE_PRIVATE
6 | import android.graphics.Color
7 | import android.graphics.Color.*
8 | import android.graphics.Paint
9 | import kotlinx.android.synthetic.main.activity_main.*
10 | import leko.valmx.thegameoflife.R
11 | import leko.valmx.thegameoflife.game.animations.Animation
12 | import leko.valmx.thegameoflife.recyclers.ThemeAdapter
13 |
14 | class GameColors(val gameView: GameView) {
15 |
16 | val cell = Paint()
17 | val background = Paint()
18 | val actorDyingPaint = Paint()
19 | val actorAlivePaint = Paint()
20 | val gridPaint = Paint()
21 | val iconPaint = Paint()
22 | val ui = Paint()
23 | val toolPaint = Paint()
24 | val toolStrokePaint = Paint()
25 |
26 | fun init() {
27 |
28 |
29 | actorDyingPaint.color = RED
30 | actorAlivePaint.color = GREEN
31 |
32 | }
33 |
34 | interface ThemeUpdateListener {
35 | fun onThemeUpdated()
36 | }
37 |
38 | fun applyTheme(bundle: ThemeAdapter.ThemeBundle, updateListener: ThemeUpdateListener) {
39 |
40 | val animationManager = gameView.animationManager
41 |
42 | val bgNew = bundle.back
43 | val cellNew = bundle.cell
44 | val gridNew = bundle.grid
45 | val uiNew = bundle.ui
46 | val iconNew = bundle.icon
47 | val toolStrokeNew = bundle.toolStroke
48 | val toolNew = bundle.tool
49 |
50 | val bgOld = background.color
51 | val cellOld = cell.color
52 | val gridOld = gridPaint.color
53 | val iconOld = bundle.icon
54 | val uiOld = bundle.ui
55 | val toolOld = toolPaint.color
56 | val toolStrokeOld = toolStrokePaint.color
57 |
58 |
59 | animationManager.animations.add(object : Animation() {
60 | override fun onAnimate(animatedValue: Float) {
61 |
62 | background.color = multiplyColorWithScalar(bgOld, bgNew, animatedValue)
63 | gridPaint.color = multiplyColorWithScalar(gridOld, gridNew, animatedValue)
64 | cell.color = multiplyColorWithScalar(cellOld, cellNew, animatedValue)
65 | ui.color = multiplyColorWithScalar(uiOld, uiNew, animatedValue)
66 | iconPaint.color = multiplyColorWithScalar(iconOld, iconNew, animatedValue)
67 | toolPaint.color = multiplyColorWithScalar(toolOld, toolNew, animatedValue)
68 | toolStrokePaint.color =
69 | multiplyColorWithScalar(toolStrokeOld, toolStrokeNew, animatedValue)
70 | animLength = 450L
71 | updateListener.onThemeUpdated()
72 |
73 | }
74 |
75 | override fun onAnimationFinished() {
76 |
77 | }
78 |
79 | override fun onAnimationStart() {
80 |
81 | }
82 |
83 | })
84 |
85 |
86 | }
87 |
88 | fun applyPreviewTheme() {
89 | cell.color = BLACK
90 | background.color = WHITE
91 | }
92 |
93 | val PREF_ID = "CGOL_VALGAMES"
94 |
95 | fun loadSavedTheme(ctx: Context) {
96 |
97 | val resources = ctx.resources
98 | val prefs = ctx.getSharedPreferences(PREF_ID, MODE_PRIVATE)
99 |
100 | val bundle = ThemeAdapter.ThemeBundle(
101 | prefs.getInt("BACK", resources.getColor(R.color.back_1)),
102 | prefs.getInt("CELL", resources.getColor(R.color.cell_1)),
103 | prefs.getInt("GRID", resources.getColor(R.color.grid_1)),
104 | prefs.getInt("UI", resources.getColor(R.color.ui_1)),
105 | prefs.getInt("ICON", resources.getColor(R.color.icon_1)),
106 | prefs.getInt("TOOL", resources.getColor(R.color.icon_1)),
107 | prefs.getInt("TOOL_STROKE", resources.getColor(R.color.icon_1)),
108 | )
109 |
110 | gridPaint.color = bundle.grid
111 | background.color = bundle.back
112 | cell.color = bundle.cell
113 | ui.color = bundle.ui
114 | iconPaint.color = bundle.icon
115 | toolPaint.color = bundle.tool
116 | toolStrokePaint.color = bundle.toolStroke
117 | }
118 |
119 |
120 | @SuppressLint("NewApi")
121 | fun multiplyColorWithScalar(color: Int, color2: Int, s: Float): Int {
122 |
123 |
124 | val R = ((1 - s) * Color.red(color) + s * Color.red(color2) + 0.5).toInt()
125 | val G = ((1 - s) * Color.green(color) + s * Color.green(color2) + 0.5).toInt()
126 | val B = ((1 - s) * Color.blue(color) + s * Color.blue(color2) + 0.5).toInt()
127 |
128 | return Color.rgb(R, G, B).toInt()
129 |
130 | }
131 |
132 |
133 | }
--------------------------------------------------------------------------------
/app/src/main/java/leko/valmx/thegameoflife/game/tools/PasteTool.kt:
--------------------------------------------------------------------------------
1 | package leko.valmx.thegameoflife.game.tools
2 |
3 | import android.graphics.Rect
4 | import android.graphics.RectF
5 | import android.widget.Toast
6 | import androidx.core.graphics.toRectF
7 | import leko.valmx.thegameoflife.R
8 | import leko.valmx.thegameoflife.game.GameView
9 | import leko.valmx.thegameoflife.recyclers.ContextToolsAdapter
10 | import leko.valmx.thegameoflife.utils.blueprints.Blueprint
11 | import java.util.*
12 | import kotlin.math.roundToInt
13 |
14 | class PasteTool(val game: GameView, val blueprint: Blueprint) :
15 | SelectionTool(game) {
16 |
17 | init {
18 | val gridManager = game.gridManager
19 |
20 | val canvas = game.canvas
21 |
22 | val h = blueprint.height
23 | val w = blueprint.width
24 |
25 | var step = gridManager.cellWidth
26 |
27 | val gameWidth = canvas.width / step
28 |
29 | if (gameWidth < w) {
30 | gridManager.cellWidth = (canvas.width / w).toFloat()
31 | }
32 | val gameHeight = canvas.height / gridManager.cellWidth
33 |
34 | if (gameHeight < h) {
35 | gridManager.cellWidth = (canvas.height / h).toFloat()
36 | }
37 |
38 | step = gridManager.cellWidth
39 |
40 | val startX = (gridManager.xOffset / step).roundToInt()
41 | val startY = (gridManager.yOffset / step).roundToInt()
42 |
43 |
44 | toolRect = Rect(startX, startY, startX + w, startY + h).toRectF()
45 | // Centering the rect
46 | toolRect!!.offset(
47 | ((canvas.width - w * step) / 2) / step,
48 | ((canvas.height - h * step) / 2) / step
49 | )
50 | }
51 |
52 | override fun drawInteraction() {
53 | super.drawInteraction()
54 |
55 | val drawManager = game.drawManager
56 |
57 | val gridManager = game.gridManager
58 |
59 | val baseX = toolRect!!.left
60 | val baseY = toolRect!!.top
61 | val step = gridManager.cellWidth
62 |
63 | // X \land Y um wie viel das Brett verschoben ist (von 0,0)
64 | val gameX = gridManager.xOffset
65 | val gameY = gridManager.yOffset
66 |
67 | blueprint.cells.withIndex().forEach { (x, yArray) ->
68 | yArray.forEachIndexed { y, isCell ->
69 | if (isCell)
70 | drawManager.drawCellAt((baseX + x) * step - gameX, (baseY + y) * step - gameY)
71 | }
72 | }
73 |
74 | }
75 |
76 | override fun getName(): String {
77 | return "Pasting..."
78 | }
79 |
80 | override fun addContextItems(items: LinkedList) {
81 | items.add(ContextToolsAdapter.ContextTool(R.drawable.check) {
82 | applyBlueprint()
83 | game.interactionManager.registeredInteraction = null
84 | Toast.makeText(gameView.context, "Applied Blueprint", Toast.LENGTH_SHORT).show()
85 | })
86 |
87 | items.add(ContextToolsAdapter.ContextTool(R.drawable.rotate_cw) {
88 | rotate()
89 | })
90 |
91 | // Initializing the rect of the thing to be pasted
92 |
93 | allowResize = false
94 |
95 |
96 | }
97 |
98 | private fun rotate() {
99 | // Test
100 |
101 | val newToolRect = toolRect?.let {
102 | RectF(
103 | it.left,
104 | it.top,
105 | it.left + it.height(),
106 | it.top + it.width()
107 | )
108 | }
109 | toolRect = newToolRect
110 |
111 | blueprint.cells
112 | val width = blueprint.width
113 |
114 |
115 | val newCells =
116 | Array>(blueprint.height) { Array(blueprint.width) { false } }
117 |
118 | blueprint.cells.forEachIndexed { x, xRow ->
119 |
120 | xRow.forEachIndexed { y, isAlive ->
121 | try {
122 |
123 | newCells[y][width - 1 - x] = isAlive
124 | } catch (e: Exception) {
125 |
126 | }
127 | }
128 | }
129 | blueprint.cells = newCells
130 |
131 | }
132 |
133 | fun applyBlueprint() {
134 | val baseX = toolRect!!.left.toInt()
135 | val baseY = toolRect!!.top.toInt()
136 |
137 | val actorManager = game.cells
138 |
139 | blueprint.cells.forEachIndexed { x, yRow ->
140 | yRow.forEachIndexed { y, isCell ->
141 | if (isCell) {
142 | actorManager.setCurrentlyAlive(baseX + x, baseY +y)
143 | } else {
144 | actorManager.setCurrentlyDead(baseX + x, baseY + y)
145 | }
146 | }
147 | }
148 | }
149 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_blueprint_selection.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
27 |
28 |
37 |
38 |
46 |
47 |
62 |
63 |
72 |
73 |
79 |
80 |
81 |
94 |
95 |
104 |
105 |
114 |
115 |
116 |
--------------------------------------------------------------------------------