├── settings.gradle
├── app
├── src
│ └── main
│ │ ├── res
│ │ ├── values-v11
│ │ │ ├── styles.xml
│ │ │ └── themes.xml
│ │ ├── drawable-hdpi
│ │ │ ├── button_new.png
│ │ │ ├── button_pen.png
│ │ │ ├── toggle_pen.png
│ │ │ ├── button_clear.png
│ │ │ ├── button_equal.png
│ │ │ ├── button_hint.png
│ │ │ ├── button_minus.png
│ │ │ ├── button_pause.png
│ │ │ ├── button_plus.png
│ │ │ ├── ic_launcher.png
│ │ │ ├── toggle_grid.png
│ │ │ ├── button_discard.png
│ │ │ ├── button_divide.png
│ │ │ ├── button_eraser.png
│ │ │ ├── button_multiply.png
│ │ │ ├── button_pen_blue.png
│ │ │ ├── button_pencil.png
│ │ │ ├── menu_back_icon.png
│ │ │ ├── menu_help_icon.png
│ │ │ ├── menu_hint_icon.png
│ │ │ ├── menu_new_icon.png
│ │ │ ├── menu_save_icon.png
│ │ │ ├── menu_share_icon.png
│ │ │ ├── menu_undo_icon.png
│ │ │ ├── toggle_number.png
│ │ │ ├── toggle_pencil.png
│ │ │ ├── button_play_light.png
│ │ │ ├── menu_replay_icon.png
│ │ │ ├── toggle_eraser_off.png
│ │ │ ├── button_discard_light.png
│ │ │ ├── button_eraser_blue.png
│ │ │ ├── button_pencil_blue.png
│ │ │ ├── button_remove_light.png
│ │ │ ├── menu_overflow_icon.png
│ │ │ ├── menu_settings_icon.png
│ │ │ └── menu_statistics_icon.png
│ │ ├── drawable-ldpi
│ │ │ └── ic_launcher.png
│ │ ├── drawable-mdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_action_search.png
│ │ ├── drawable-xhdpi
│ │ │ ├── button_pen.png
│ │ │ ├── ic_launcher.png
│ │ │ ├── toggle_grid.png
│ │ │ ├── toggle_pen.png
│ │ │ ├── button_discard.png
│ │ │ ├── button_eraser.png
│ │ │ ├── button_pencil.png
│ │ │ ├── menu_back_icon.png
│ │ │ ├── menu_help_icon.png
│ │ │ ├── menu_hint_icon.png
│ │ │ ├── menu_new_icon.png
│ │ │ ├── menu_save_icon.png
│ │ │ ├── menu_undo_icon.png
│ │ │ ├── toggle_number.png
│ │ │ ├── toggle_pencil.png
│ │ │ ├── ic_action_search.png
│ │ │ ├── menu_replay_icon.png
│ │ │ ├── menu_share_icon.png
│ │ │ ├── button_play_light.png
│ │ │ ├── button_remove_light.png
│ │ │ ├── menu_overflow_icon.png
│ │ │ ├── menu_settings_icon.png
│ │ │ ├── toggle_eraser_off.png
│ │ │ ├── button_discard_light.png
│ │ │ └── menu_statistics_icon.png
│ │ ├── color
│ │ │ ├── text_button.xml
│ │ │ └── text_button_dark.xml
│ │ ├── drawable
│ │ │ ├── text_button.xml
│ │ │ ├── text_button_dark.xml
│ │ │ ├── menu_button.xml
│ │ │ ├── toggle_mode_bg.xml
│ │ │ ├── toggle_mode_bg_dark.xml
│ │ │ ├── radio_button.xml
│ │ │ ├── radio_button_dark.xml
│ │ │ ├── keypad_button.xml
│ │ │ └── keypad_button_dark.xml
│ │ ├── values-v13
│ │ │ └── themes.xml
│ │ ├── menu
│ │ │ ├── solutions.xml
│ │ │ └── activity_main.xml
│ │ ├── values
│ │ │ ├── themes.xml
│ │ │ ├── arrays.xml
│ │ │ ├── styles.xml
│ │ │ └── strings.xml
│ │ ├── layout
│ │ │ ├── dialog_help.xml
│ │ │ ├── dialog_about.xml
│ │ │ ├── dialog_mode.xml
│ │ │ ├── activity_savegame.xml
│ │ │ ├── object_savegame.xml
│ │ │ ├── activity_main.xml
│ │ │ └── activity_stats.xml
│ │ ├── layout-sw480dp
│ │ │ ├── object_savegame.xml
│ │ │ └── activity_main.xml
│ │ ├── xml
│ │ │ └── activity_settings.xml
│ │ ├── layout-small-land
│ │ │ └── activity_main.xml
│ │ ├── layout-land
│ │ │ └── activity_main.xml
│ │ ├── layout-small
│ │ │ └── activity_main.xml
│ │ └── layout-sw480dp-land
│ │ │ └── activity_main.xml
│ │ ├── java
│ │ └── com
│ │ │ ├── srlee
│ │ │ └── DLX
│ │ │ │ ├── DLXRow.java
│ │ │ │ ├── DLXColumn.java
│ │ │ │ ├── DLXNode.java
│ │ │ │ ├── LL2DNode.java
│ │ │ │ ├── LatinSquareDLX.java
│ │ │ │ ├── MathDokuDLX.java
│ │ │ │ └── DLX.java
│ │ │ ├── holokenmod
│ │ │ ├── Utils.java
│ │ │ ├── UndoList.java
│ │ │ ├── UndoState.java
│ │ │ ├── SettingsActivity.java
│ │ │ ├── StatsActivity.java
│ │ │ ├── SaveGameListAdapter.java
│ │ │ ├── SaveGameListActivity.java
│ │ │ ├── SaveGame.java
│ │ │ ├── GridCell.java
│ │ │ └── GridCage.java
│ │ │ └── mobiRic
│ │ │ └── ui
│ │ │ └── widget
│ │ │ └── Boast.java
│ │ └── AndroidManifest.xml
└── build.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── README.md
├── .gitattributes
├── .gitignore
├── .travis.yml
├── gradlew.bat
└── gradlew
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/app/src/main/res/values-v11/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/button_new.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-hdpi/button_new.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/button_pen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-hdpi/button_pen.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/toggle_pen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-hdpi/toggle_pen.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/button_clear.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-hdpi/button_clear.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/button_equal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-hdpi/button_equal.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/button_hint.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-hdpi/button_hint.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/button_minus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-hdpi/button_minus.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/button_pause.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-hdpi/button_pause.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/button_plus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-hdpi/button_plus.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/toggle_grid.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-hdpi/toggle_grid.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-ldpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-ldpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/button_pen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-xhdpi/button_pen.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/toggle_grid.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-xhdpi/toggle_grid.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/toggle_pen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-xhdpi/toggle_pen.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/button_discard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-hdpi/button_discard.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/button_divide.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-hdpi/button_divide.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/button_eraser.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-hdpi/button_eraser.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/button_multiply.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-hdpi/button_multiply.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/button_pen_blue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-hdpi/button_pen_blue.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/button_pencil.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-hdpi/button_pencil.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/menu_back_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-hdpi/menu_back_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/menu_help_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-hdpi/menu_help_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/menu_hint_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-hdpi/menu_hint_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/menu_new_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-hdpi/menu_new_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/menu_save_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-hdpi/menu_save_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/menu_share_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-hdpi/menu_share_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/menu_undo_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-hdpi/menu_undo_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/toggle_number.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-hdpi/toggle_number.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/toggle_pencil.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-hdpi/toggle_pencil.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/button_discard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-xhdpi/button_discard.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/button_eraser.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-xhdpi/button_eraser.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/button_pencil.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-xhdpi/button_pencil.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/menu_back_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-xhdpi/menu_back_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/menu_help_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-xhdpi/menu_help_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/menu_hint_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-xhdpi/menu_hint_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/menu_new_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-xhdpi/menu_new_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/menu_save_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-xhdpi/menu_save_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/menu_undo_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-xhdpi/menu_undo_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/toggle_number.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-xhdpi/toggle_number.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/toggle_pencil.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-xhdpi/toggle_pencil.png
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | holoken-dev
2 | ===========
3 | 
4 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/button_play_light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-hdpi/button_play_light.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/menu_replay_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-hdpi/menu_replay_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/toggle_eraser_off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-hdpi/toggle_eraser_off.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_action_search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-mdpi/ic_action_search.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_action_search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-xhdpi/ic_action_search.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/menu_replay_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-xhdpi/menu_replay_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/menu_share_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-xhdpi/menu_share_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/button_discard_light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-hdpi/button_discard_light.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/button_eraser_blue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-hdpi/button_eraser_blue.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/button_pencil_blue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-hdpi/button_pencil_blue.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/button_remove_light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-hdpi/button_remove_light.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/menu_overflow_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-hdpi/menu_overflow_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/menu_settings_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-hdpi/menu_settings_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/menu_statistics_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-hdpi/menu_statistics_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/button_play_light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-xhdpi/button_play_light.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/button_remove_light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-xhdpi/button_remove_light.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/menu_overflow_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-xhdpi/menu_overflow_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/menu_settings_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-xhdpi/menu_settings_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/toggle_eraser_off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-xhdpi/toggle_eraser_off.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/button_discard_light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-xhdpi/button_discard_light.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/menu_statistics_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queler/holokenmod/HEAD/app/src/main/res/drawable-xhdpi/menu_statistics_icon.png
--------------------------------------------------------------------------------
/app/src/main/java/com/srlee/DLX/DLXRow.java:
--------------------------------------------------------------------------------
1 | package com.srlee.DLX;
2 |
3 |
4 | public class DLXRow
5 | {
6 | public DLXRow(DLXNode first)
7 | {
8 | FirstNode = first;
9 | }
10 |
11 | public DLXNode FirstNode;
12 | }
13 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Apr 03 14:47:23 EDT 2020
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip
7 |
--------------------------------------------------------------------------------
/app/src/main/res/color/text_button.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/color/text_button_dark.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/text_button.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/text_button_dark.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values-v13/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/java/com/srlee/DLX/DLXColumn.java:
--------------------------------------------------------------------------------
1 | package com.srlee.DLX;
2 |
3 |
4 | public class DLXColumn extends LL2DNode
5 | {
6 | private int size; // Number of items in column
7 | public DLXColumn()
8 | {
9 | size = 0;
10 | SetUp(this);
11 | SetDown(this);
12 | }
13 | public int GetSize() { return size; }
14 | public void DecSize() { size--; }
15 | public void IncSize() { size++; }
16 | }
17 |
--------------------------------------------------------------------------------
/app/src/main/java/com/holokenmod/Utils.java:
--------------------------------------------------------------------------------
1 | package com.holokenmod;
2 |
3 | import android.os.Build;
4 |
5 | public class Utils {
6 | public static String convertTimetoStr(long time) {
7 | int seconds = (int) (time / 1000);
8 | int minutes = seconds / 60 % 60;
9 | int hours = seconds / 3600;
10 | seconds = seconds % 60;
11 |
12 | return String.format("%02d:%02d:%02d", hours, minutes, seconds);
13 | }
14 |
15 | public static boolean hasHoneycomb() {
16 | return Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB;
17 | }
18 |
19 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/srlee/DLX/DLXNode.java:
--------------------------------------------------------------------------------
1 | package com.srlee.DLX;
2 |
3 |
4 | public class DLXNode extends LL2DNode
5 | {
6 | public DLXNode(DLXColumn col, int ri)
7 | {
8 | RowIdx = ri;
9 | C = col;
10 | col.GetUp().SetDown(this);
11 | SetUp(col.GetUp());
12 | SetDown(col);
13 | col.SetUp(this);
14 | col.IncSize();
15 | }
16 | public DLXColumn GetColumn() { return C; }
17 | public int GetRowIdx() { return RowIdx; }
18 |
19 | private DLXColumn C; // Pointer to Column Header
20 | private int RowIdx; // Index to row
21 | }
22 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Set the default behavior, in case people don't have core.autocrlf set.
2 |
3 | # Explicitly declare text files you want to always be normalized and converted
4 | # to native line endings on checkout.
5 | *.c text
6 | *.h text
7 | *.java text eol=lf
8 |
9 |
10 | # Declare files that will always have CRLF line endings on checkout.
11 | *.sln text eol=crlf
12 | *.bat text eol-crlf
13 | gradlew text eol=lf
14 | *.gradle text eol=lf
15 | .properties text eol=lf
16 |
17 |
18 | # Denote all files that are truly binary and should not be modified.
19 | *.png binary
20 | *.jpg binary
21 | *.jar binary
22 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | #built application files
2 | *.apk
3 | *.ap_
4 |
5 | # files for the dex VM
6 | *.dex
7 |
8 | # Java class files
9 | *.class
10 |
11 | # generated files
12 | bin/
13 | gen/
14 |
15 | # Local configuration file (sdk path, etc)
16 | local.properties
17 |
18 | # Windows thumbnail db
19 | Thumbs.db
20 |
21 | # OSX files
22 | .DS_Store
23 |
24 | # Eclipse project files
25 | .classpath
26 | .project
27 |
28 | # Android Studio
29 | *.iml
30 | .idea
31 | #.idea/workspace.xml - remove # and delete .idea if it better suit your needs.
32 | .gradle
33 | build/
34 |
35 | #NDK
36 | obj/
--------------------------------------------------------------------------------
/app/src/main/res/menu/solutions.xml:
--------------------------------------------------------------------------------
1 |
13 |
14 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | android {
3 | compileSdkVersion 22
4 | buildToolsVersion '29.0.3'
5 | lintOptions {
6 | disable "ExpiredTargetSdkVersion"
7 | }
8 | defaultConfig {
9 | applicationId "com.holokenmod"
10 | minSdkVersion 8
11 | targetSdkVersion 22
12 | }
13 |
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
18 | }
19 | }
20 | }
21 | repositories {
22 | google()
23 | }
24 |
25 | dependencies {
26 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/menu_button.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | -
6 |
7 |
8 |
9 |
10 |
11 | -
12 |
13 |
14 |
15 |
16 |
17 | -
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/values-v11/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
10 |
--------------------------------------------------------------------------------
/app/src/main/java/com/holokenmod/UndoList.java:
--------------------------------------------------------------------------------
1 | package com.holokenmod;
2 |
3 | import java.util.LinkedList;
4 |
5 | @SuppressWarnings("serial")
6 | public class UndoList extends LinkedList {
7 | private int maxSize;
8 |
9 | public UndoList(int maxSize) {
10 | this.maxSize = maxSize;
11 | }
12 |
13 | @Override
14 | public synchronized boolean add(UndoState object) {
15 | //if (size() == maxSize)
16 | // removeFirst();
17 | return super.add(object);
18 | }
19 |
20 | @Override
21 | public synchronized UndoState removeFirst() {
22 | return super.removeFirst();
23 | }
24 |
25 | @Override
26 | public synchronized UndoState removeLast() {
27 | return super.removeLast();
28 | }
29 |
30 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/srlee/DLX/LL2DNode.java:
--------------------------------------------------------------------------------
1 | package com.srlee.DLX;
2 |
3 | public class LL2DNode extends Object
4 | {
5 | public void SetLeft(LL2DNode left) { L = left; }
6 | public void SetRight(LL2DNode right) { R = right; }
7 | public void SetUp(LL2DNode up) { U = up; }
8 | public void SetDown(LL2DNode down) { D = down; }
9 | public LL2DNode GetLeft() { return L; }
10 | public LL2DNode GetRight() { return R; }
11 | public LL2DNode GetUp() { return U; }
12 | public LL2DNode GetDown() { return D; }
13 | public LL2DNode()
14 | {
15 | L = R = U = D = null;
16 | }
17 |
18 | private LL2DNode L; // Pointer to left node
19 | private LL2DNode R; // Pointer to right node
20 | private LL2DNode U; // Pointer to node above
21 | private LL2DNode D; // Pointer to node below
22 | }
23 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/toggle_mode_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | -
5 |
6 |
7 |
10 |
11 |
12 | -
13 |
14 |
15 |
18 |
19 |
20 | -
21 |
22 |
23 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/toggle_mode_bg_dark.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | -
5 |
6 |
7 |
10 |
11 |
12 | -
13 |
14 |
15 |
18 |
19 |
20 | -
21 |
22 |
23 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: android
2 | android:
3 | components:
4 | - tools
5 | - build-tools-29.0.3
6 | - android-22
7 | script:
8 | - "./gradlew assembleDebug"
9 | deploy:
10 | skip_cleanup: true
11 | provider: releases
12 | api_key:
13 | secure: q5kCGbUuFaquVAWcNjPGAWuYXqs5MzWqtpVB/8maxFtKPRe7kby/invpqryA1ZOCwN3TeVEXSa97W15ks65RneQpBG9N3rj+C53nZucUzgJJ0kuh1edJDHSZwuqV3LU+1cbyeN03RbJGMkMIqbYX+1zmCDq31GbxYDMC2j8+TO8zX6bXlcuizvOv/x97jrGZTFJrCWZFM4zhA9z6R9Bmb6DLzg6Ay91kWKFS4jq8SzHodWnBqAsxcLRCtnB4ycX6dVtZNoMRJNs5GA3QjTNqA2JCFH/X6/0fDxfWfxanXQqfrspPtyb/e2Yd2VTQ6BMFbbI4pm7l+NRkyKlO9/G7WSMZmdLhb4MtBHViEAJnkeq8GByYkK3FrX40dU9bXVivqbgHapSChob5ychE/Sz2SgGWmHfp4fRsNQKM4Mu1HlORhYnSFvh+pbi92tZOhr8dPT+yt22MbKwKGr+J5MOVtBh6EOrFfPtWDsVTvTSUTnm9ADUQWzK9iRcKJLJyJTaQlNTdscfmfizSFSGT8Wh1XSK5kI8WWAvX+JLBoZWSh3gx6V19sjNShPQtNvlapQMXTgfim2JBMSoNwhwElkKKHbRyY859gVj43OWnmNYgOAWP5hlLJPKNNCJslITRM2UVMvGuJzvVPYJ6zQ2F8X60KQX9Qnby81KtpcdMFz9HlJI=
14 | file: app/build/outputs/apk/debug/app-debug.apk
15 | on:
16 | repo: queler/holokenmod
17 | all_branches: true
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/dialog_help.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
13 |
15 |
17 |
19 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/radio_button.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | -
6 |
7 |
8 |
11 |
12 |
13 |
14 | -
16 |
17 |
18 |
21 |
22 |
23 | -
24 |
25 |
26 |
29 |
30 |
31 | -
32 |
33 |
34 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/radio_button_dark.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | -
6 |
7 |
8 |
11 |
12 |
13 |
14 | -
16 |
17 |
18 |
21 |
22 |
23 | -
24 |
25 |
26 |
29 |
30 |
31 | -
32 |
33 |
34 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/app/src/main/java/com/srlee/DLX/LatinSquareDLX.java:
--------------------------------------------------------------------------------
1 | package com.srlee.DLX;
2 |
3 | import java.util.ArrayList;
4 |
5 | import com.holokenmod.GridCell;
6 |
7 |
8 | public class LatinSquareDLX extends DLX {
9 |
10 | private int BOARD = 0;
11 | private int BOARD2 = 0;
12 | private int BOARD3 = 0;
13 |
14 | public LatinSquareDLX (int n, ArrayList cells)
15 | {
16 | BOARD = n;
17 | BOARD2 = BOARD * BOARD;
18 | BOARD3 = BOARD2 * BOARD;
19 |
20 | Init(BOARD2 * 3, BOARD3, BOARD3 * 3);
21 |
22 | int d, r, c;
23 | int moveidx = 0;
24 |
25 | // Setup all possible "moves" and the conditions they affect
26 | for (d = 1; d <= BOARD; d++)
27 | for (r = 1; r <= BOARD; r++)
28 | for (c = 1; c <= BOARD; c++)
29 | {
30 | AddNode((r - 1) * BOARD + c, moveidx); //
31 | AddNode(BOARD2 + (d - 1) * BOARD + r, moveidx); //
32 | AddNode(BOARD2 * 2 + (d - 1) * BOARD + c, moveidx); //
33 | moveidx++;
34 | }
35 |
36 | // Now apply the "moves" we already know
37 | for (GridCell cell : cells)
38 | if (cell.mValue != 0)
39 | if (!GivenRow((cell.mValue - 1)* BOARD2 + cell.mRow * BOARD + cell.mColumn + 1)) {
40 | isValid = false;
41 | return;
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
5 |
10 |
11 |
12 |
17 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
29 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/activity_main.xml:
--------------------------------------------------------------------------------
1 |
32 |
--------------------------------------------------------------------------------
/app/src/main/java/com/holokenmod/UndoState.java:
--------------------------------------------------------------------------------
1 |
2 | package com.holokenmod;
3 |
4 | import java.util.ArrayList;
5 | import java.util.Collections;
6 | import java.util.List;
7 |
8 | public class UndoState {
9 |
10 | public int cellNum;
11 | public int userValue;
12 | public List possibles;
13 | public boolean batch;
14 |
15 | public UndoState (int cellNum, int userValue, List Possibles) {
16 | this.cellNum = cellNum;
17 | this.userValue = userValue;
18 | this.possibles = copyArrayList(Possibles);
19 | this.batch = false;
20 | }
21 |
22 | public UndoState (int cellNum, int userValue, List Possibles, boolean batch) {
23 | this.cellNum = cellNum;
24 | this.userValue = userValue;
25 | this.possibles = copyArrayList(Possibles);
26 | this.batch = batch;
27 | }
28 |
29 | public int getCellNum () {
30 | return this.cellNum;
31 | }
32 |
33 | public int getUserValue() {
34 | return this.userValue;
35 | }
36 |
37 | public List getPossibles() {
38 | return this.possibles;
39 | }
40 |
41 | public boolean getBatch() {
42 | return this.batch;
43 | }
44 |
45 | public List copyArrayList(List oldlist) {
46 | List copylist = Collections.synchronizedList( new ArrayList(oldlist));
47 | Collections.copy(copylist,oldlist);
48 | return copylist;
49 | }
50 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/keypad_button.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | -
6 |
7 |
8 |
11 |
12 |
13 |
14 | -
15 |
16 |
17 |
20 |
21 |
22 |
23 | -
24 |
25 |
26 |
29 |
30 |
31 |
32 | -
33 |
34 |
35 |
38 |
39 |
40 |
41 | -
42 |
43 |
44 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/keypad_button_dark.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | -
6 |
7 |
8 |
11 |
12 |
13 |
14 | -
15 |
16 |
17 |
20 |
21 |
22 |
23 | -
24 |
25 |
26 |
29 |
30 |
31 |
32 | -
33 |
34 |
35 |
38 |
39 |
40 |
41 | -
42 |
43 |
44 |
45 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/dialog_about.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
13 |
15 |
17 |
19 |
21 |
23 |
25 |
27 |
29 |
31 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/dialog_mode.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
15 |
16 |
22 |
27 |
32 |
37 |
38 |
44 |
45 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_savegame.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
17 |
18 |
22 |
26 |
27 |
28 |
31 |
32 |
36 |
37 |
44 |
--------------------------------------------------------------------------------
/app/src/main/java/com/srlee/DLX/MathDokuDLX.java:
--------------------------------------------------------------------------------
1 | package com.srlee.DLX;
2 |
3 | import java.util.ArrayList;
4 |
5 | import com.holokenmod.GridCage;
6 |
7 |
8 | public class MathDokuDLX extends DLX {
9 |
10 | private int BOARD = 0;
11 | private int BOARD2 = 0;
12 |
13 | public MathDokuDLX(int size, ArrayList cages) {
14 |
15 | BOARD = size;
16 | BOARD2 = BOARD * BOARD;
17 |
18 | // Number of columns = number of constraints =
19 | // BOARD * BOARD (for columns) +
20 | // BOARD * BOARD (for rows) +
21 | // Num cages (each cage has to be filled once and only once)
22 | // Number of rows = number of "moves" =
23 | // Sum of all the possible cage combinations
24 | // Number of nodes = sum of each move:
25 | // num_cells column constraints +
26 | // num_cells row constraints +
27 | // 1 (cage constraint)
28 | int total_moves=0;
29 | int total_nodes=0;
30 | for (GridCage gc : cages) {
31 | total_moves += gc.getPossibleNums().size();
32 | total_nodes += gc.getPossibleNums().size()*(2*gc.mCells.size()+1);
33 | }
34 | Init (2*BOARD2 + cages.size(), total_moves, total_nodes);
35 |
36 | int constraint_num;
37 | int move_idx = 0;
38 | for (GridCage gc : cages)
39 | {
40 | ArrayList allmoves = gc.getPossibleNums();
41 | for (int[] onemove : allmoves)
42 | {
43 | for (int i = 0; i
2 |
8 |
9 |
16 |
17 |
25 |
26 |
30 |
33 |
34 |
37 |
42 |
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/app/src/main/res/values/arrays.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | - Ask before game starts
7 | - 4x4 (Easy)
8 | - 5x5 (Medium)
9 | - 6x6 (Hard)
10 | - 7x7 (Harder)
11 | - 8x8 (Hardest)
12 | - 9x9 (Ultimate)
13 |
14 |
15 |
16 | - ask
17 | - 4
18 | - 5
19 | - 6
20 | - 7
21 | - 8
22 | - 9
23 |
24 |
25 |
26 |
27 | - Ask before game starts
28 | - All mathematical operations
29 | - Addition and subtraction
30 | - Addition and multiplication
31 | - Multiplication only
32 |
33 |
34 |
35 | - ask
36 | - 0
37 | - 1
38 | - 2
39 | - 3
40 |
41 |
42 |
43 |
44 | - Ask before game starts
45 | - Always show operators
46 | - Never show operators
47 |
48 |
49 |
50 | - ask
51 | - true
52 | - false
53 |
54 |
55 |
56 | - Holo Light
57 | - Holo Dark
58 |
59 |
60 | - 0
61 | - 1
62 |
63 |
64 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/object_savegame.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
17 |
18 |
26 |
27 |
31 |
34 |
35 |
38 |
43 |
48 |
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/app/src/main/java/com/holokenmod/SettingsActivity.java:
--------------------------------------------------------------------------------
1 | package com.holokenmod;
2 |
3 | import android.content.Intent;
4 | import android.content.SharedPreferences;
5 | import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
6 | import android.net.Uri;
7 | import android.os.Bundle;
8 | import android.preference.Preference;
9 | import android.preference.Preference.OnPreferenceClickListener;
10 | import android.preference.PreferenceActivity;
11 | import android.preference.PreferenceManager;
12 | import android.view.WindowManager;
13 |
14 | public class SettingsActivity extends PreferenceActivity implements OnSharedPreferenceChangeListener {
15 |
16 | @Override
17 | public void onCreate(Bundle savedInstanceState) {
18 | super.onCreate(savedInstanceState);
19 | if (!PreferenceManager.getDefaultSharedPreferences(this).getBoolean("showfullscreen", false))
20 | this.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
21 | else
22 | this.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
23 |
24 | // Deprecated addPreferencesFromResources, use fragments instead?
25 | addPreferencesFromResource(R.xml.activity_settings);
26 |
27 | Preference ratePref = findPreference("rateapp");
28 | ratePref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
29 | public boolean onPreferenceClick(Preference preference) {
30 | Intent intent = new Intent(Intent.ACTION_VIEW);
31 | try {
32 | intent.setData(Uri.parse("market://details?id=" ));
33 | startActivity(intent);
34 | return true;
35 | }
36 | catch (Exception e) {
37 | intent.setData(Uri.parse("http://play.google.com/store/apps/details?id="+getApplicationContext().getPackageName()));
38 | startActivity(intent);
39 | return false;
40 | }
41 | }
42 | });
43 |
44 | Preference reportBugs = findPreference("reportbugs");
45 | reportBugs.setOnPreferenceClickListener(new OnPreferenceClickListener() {
46 | public boolean onPreferenceClick(Preference preference) {
47 | Intent intent = new Intent(Intent.ACTION_VIEW);
48 | intent.setData(Uri.parse("https://github.com/queler/holokenmod/issues"));
49 | startActivity(intent);
50 | return true;
51 | }
52 | });
53 | }
54 |
55 | public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
56 |
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
13 |
14 |
19 |
20 |
27 |
28 |
31 |
32 |
36 |
37 |
42 |
43 |
53 |
54 |
61 |
62 |
66 |
67 |
71 |
72 |
75 |
76 |
80 |
81 |
86 |
87 |
91 |
92 |
97 |
--------------------------------------------------------------------------------
/app/src/main/java/com/holokenmod/StatsActivity.java:
--------------------------------------------------------------------------------
1 | package com.holokenmod;
2 |
3 | import android.app.Activity;
4 | import android.content.SharedPreferences;
5 | import android.os.Bundle;
6 | import android.preference.PreferenceManager;
7 | import android.view.View;
8 | import android.view.WindowManager;
9 | import android.view.View.OnClickListener;
10 | import android.widget.Button;
11 | import android.widget.TextView;
12 |
13 | public class StatsActivity extends Activity {
14 |
15 | SharedPreferences stats;
16 | long bestTimeStat[] = new long[6];
17 | long avgTimeStat[] = new long[6];
18 | int totalStarted = 0;
19 | int totalSolved = 0;
20 | int totalHinted = 0;
21 |
22 | TextView timeView[] = new TextView[6];
23 | TextView startedGamesView, solvedGamesView, hintedGamesView;
24 | TextView solvedStreakView, longestStreakView;
25 |
26 | @Override
27 | public void onCreate(Bundle savedInstanceState) {
28 | super.onCreate(savedInstanceState);
29 | if (!PreferenceManager.getDefaultSharedPreferences(this).getBoolean("showfullscreen", false))
30 | this.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
31 | else
32 | this.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
33 |
34 | //quick and dirty stats using sharedpref instead of sqlite
35 | this.stats = getSharedPreferences("stats", MODE_PRIVATE);
36 |
37 | setContentView(R.layout.activity_stats);
38 | timeView[0] = (TextView)findViewById(R.id.gridtime4);
39 | timeView[1] = (TextView)findViewById(R.id.gridtime5);
40 | timeView[2] = (TextView)findViewById(R.id.gridtime6);
41 | timeView[3] = (TextView)findViewById(R.id.gridtime7);
42 | timeView[4] = (TextView)findViewById(R.id.gridtime8);
43 | timeView[5] = (TextView)findViewById(R.id.gridtime9);
44 |
45 | startedGamesView = (TextView)findViewById(R.id.startedstat);
46 | hintedGamesView = (TextView)findViewById(R.id.hintedstat);
47 | solvedGamesView = (TextView)findViewById(R.id.solvedstat);
48 | solvedStreakView = (TextView)findViewById(R.id.solvedstreak);
49 | longestStreakView = (TextView)findViewById(R.id.longeststreak);
50 |
51 | Button clearStats = (Button)findViewById(R.id.clearstats);
52 |
53 | clearStats.setOnClickListener(new OnClickListener() {
54 | public void onClick(View v) {
55 | SharedPreferences.Editor editor = stats.edit();
56 | editor.clear().commit();
57 | totalStarted = 0;
58 | totalSolved = 0;
59 | totalHinted = 0;
60 | fillStats();
61 | }
62 | });
63 |
64 | fillStats();
65 | }
66 |
67 |
68 | public void fillStats() {
69 | for (int i=0; i
2 |
4 |
5 |
12 |
19 |
26 |
27 |
28 |
29 |
35 |
39 |
45 |
49 |
53 |
57 |
58 |
59 |
60 |
64 |
68 |
73 |
74 |
75 |
76 |
80 |
84 |
85 |
--------------------------------------------------------------------------------
/app/src/main/java/com/holokenmod/SaveGameListAdapter.java:
--------------------------------------------------------------------------------
1 | package com.holokenmod;
2 |
3 | import android.content.SharedPreferences;
4 | import android.preference.PreferenceManager;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.View.OnClickListener;
8 | import android.view.ViewGroup;
9 | import android.widget.BaseAdapter;
10 | import android.widget.ImageButton;
11 | import android.widget.TextView;
12 |
13 | import java.io.File;
14 | import java.text.DateFormat;
15 | import java.util.ArrayList;
16 | import java.util.Calendar;
17 | import java.util.Collections;
18 | import java.util.Comparator;
19 | import java.util.List;
20 |
21 | public class SaveGameListAdapter extends BaseAdapter {
22 |
23 | public ArrayList mGameFiles;
24 | private LayoutInflater inflater;
25 | private SaveGameListActivity mContext;
26 | //private Typeface mFace;
27 |
28 | public SharedPreferences preferences;
29 |
30 | public SaveGameListAdapter(SaveGameListActivity context) {
31 | this.inflater = LayoutInflater.from(context);
32 | this.mContext = context;
33 | this.mGameFiles = new ArrayList();
34 | this.refreshFiles();
35 | }
36 |
37 | public class SortSavedGames implements Comparator {
38 | long save1 = 0;
39 | long save2 = 0;
40 | public int compare(String object1, String object2) {
41 | try {
42 | save1 = new SaveGame(mContext.getFilesDir().getPath() + "/" + object1).ReadDate();
43 | save2 = new SaveGame(mContext.getFilesDir().getPath() + "/" + object2).ReadDate();
44 | }
45 | catch (Exception e) {
46 | //
47 | }
48 | return (int) ((save2 - save1)/1000);
49 | }
50 |
51 | }
52 |
53 | public void refreshFiles() {
54 | this.mGameFiles.clear();
55 | File dir = mContext.getFilesDir();
56 | String[] allFiles = dir.list();
57 | for (String entryName : allFiles)
58 | if (entryName.startsWith("savegame_"))
59 | this.mGameFiles.add(entryName);
60 | Collections.sort(this.mGameFiles, new SortSavedGames());
61 | }
62 |
63 | public int getCount() {
64 | return this.mGameFiles.size();
65 | }
66 |
67 | public Object getItem(int arg0) {
68 | //if (arg0 == 0)
69 | // return "";
70 | return this.mGameFiles.get(arg0);
71 | }
72 |
73 | public long getItemId(int position) {
74 | return position;
75 | }
76 |
77 | public View getView(int position, View convertView, ViewGroup parent) {
78 | convertView = inflater.inflate(R.layout.object_savegame, null);
79 |
80 | GridView grid = (GridView)convertView.findViewById(R.id.saveGridView);
81 | TextView gametitle = (TextView)convertView.findViewById(R.id.saveGameTitle);
82 | TextView datetime = (TextView)convertView.findViewById(R.id.saveDateTime);
83 |
84 | final String saveFile = mContext.getFilesDir().getPath() + "/"+ this.mGameFiles.get(position);
85 |
86 | this.preferences = PreferenceManager.getDefaultSharedPreferences(convertView.getContext());
87 | grid.mContext = this.mContext;
88 | grid.mActive = false;
89 | grid.mDupedigits = this.preferences.getBoolean("duplicates", true);
90 | grid.mBadMaths = this.preferences.getBoolean("badmaths", true);
91 |
92 | //grid.setTheme(theme);
93 | String themePref = this.preferences.getString("alternatetheme", "0");
94 | int theme = Integer.parseInt(themePref);
95 | convertView.findViewById(R.id.saveGameRow).setBackgroundColor(
96 | MainActivity.BG_COLOURS[theme]);
97 | gametitle.setTextColor(MainActivity.TEXT_COLOURS[theme]);
98 | datetime.setTextColor(MainActivity.TEXT_COLOURS[theme]);
99 |
100 | SaveGame saver = new SaveGame(saveFile);
101 | try {
102 | saver.Restore(grid);
103 | }
104 | catch (Exception e) {
105 | // Error, delete the file.
106 | new File(saveFile).delete();
107 | return convertView;
108 | }
109 | grid.setBackgroundColor(0xFFFFFFFF);
110 | for (GridCell cell : grid.mCells)
111 | cell.mSelected = false;
112 |
113 | long millis = grid.mPlayTime;
114 | gametitle.setText(String.format("%dx%d - ", grid.mGridSize,
115 | grid.mGridSize) + Utils.convertTimetoStr(millis));
116 |
117 | Calendar gameDateTime = Calendar.getInstance();
118 | gameDateTime.setTimeInMillis(grid.mDate);
119 | datetime.setText("" + DateFormat.getDateTimeInstance(
120 | DateFormat.MEDIUM, DateFormat.SHORT).format(grid.mDate));
121 |
122 | ImageButton loadButton = (ImageButton)convertView.findViewById(R.id.button_play);
123 | loadButton.setOnClickListener(new OnClickListener() {
124 | public void onClick(View v) {
125 | mContext.loadSaveGame(saveFile);
126 | }
127 | });
128 |
129 | ImageButton deleteButton = (ImageButton)convertView.findViewById(R.id.button_delete);
130 | deleteButton.setOnClickListener(new OnClickListener() {
131 | public void onClick(View v) {
132 | mContext.deleteGameDialog(saveFile);
133 | }
134 | });
135 |
136 | return convertView;
137 | }
138 |
139 | }
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
17 |
18 |
23 |
24 |
28 |
29 |
30 |
35 |
39 |
40 |
50 |
51 |
53 |
54 |
57 |
58 |
59 |
60 |
61 |
69 |
70 |
71 |
74 |
77 |
80 |
83 |
84 |
85 |
86 |
89 |
92 |
95 |
98 |
99 |
100 |
101 |
104 |
107 |
110 |
113 |
114 |
115 |
116 |
122 |
123 |
127 |
131 |
135 |
139 |
140 |
141 |
142 |
--------------------------------------------------------------------------------
/app/src/main/res/layout-small-land/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
16 |
17 |
22 |
26 |
27 |
28 |
32 |
33 |
37 |
38 |
42 |
43 |
53 |
54 |
56 |
57 |
60 |
61 |
62 |
63 |
64 |
71 |
72 |
73 |
76 |
79 |
82 |
83 |
84 |
85 |
88 |
91 |
94 |
95 |
96 |
97 |
100 |
103 |
106 |
107 |
108 |
111 |
114 |
117 |
118 |
119 |
120 |
121 |
122 |
127 |
128 |
132 |
136 |
140 |
144 |
145 |
146 |
147 |
--------------------------------------------------------------------------------
/app/src/main/res/layout-land/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
14 |
15 |
19 |
20 |
30 |
31 |
33 |
34 |
37 |
38 |
39 |
40 |
41 |
42 |
46 |
47 |
53 |
54 |
59 |
63 |
64 |
65 |
73 |
74 |
75 |
78 |
81 |
84 |
85 |
86 |
87 |
90 |
93 |
96 |
97 |
98 |
99 |
102 |
105 |
108 |
109 |
110 |
113 |
116 |
119 |
120 |
121 |
122 |
127 |
128 |
132 |
136 |
140 |
144 |
145 |
146 |
147 |
148 |
--------------------------------------------------------------------------------
/app/src/main/res/layout-sw480dp/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
18 |
19 |
26 |
27 |
33 |
34 |
38 |
39 |
40 |
44 |
45 |
48 |
49 |
59 |
60 |
62 |
63 |
66 |
67 |
68 |
69 |
78 |
79 |
80 |
83 |
86 |
89 |
92 |
93 |
94 |
95 |
98 |
101 |
104 |
107 |
108 |
109 |
110 |
113 |
116 |
119 |
122 |
123 |
124 |
125 |
131 |
132 |
136 |
140 |
144 |
148 |
149 |
150 |
151 |
--------------------------------------------------------------------------------
/app/src/main/java/com/holokenmod/SaveGameListActivity.java:
--------------------------------------------------------------------------------
1 | package com.holokenmod;
2 |
3 | import android.app.Activity;
4 | import android.app.AlertDialog;
5 | import android.app.ListActivity;
6 | import android.content.DialogInterface;
7 | import android.content.Intent;
8 | import android.os.Bundle;
9 | import android.preference.PreferenceManager;
10 | import android.view.View;
11 | import android.view.View.OnClickListener;
12 | import android.view.WindowManager;
13 | import android.widget.Button;
14 | import android.widget.ImageButton;
15 | import android.widget.ListView;
16 | import android.widget.TextView;
17 |
18 | import java.io.File;
19 | import java.io.FileInputStream;
20 | import java.io.FileOutputStream;
21 | import java.io.IOException;
22 | import java.io.InputStream;
23 | import java.io.OutputStream;
24 |
25 | public class SaveGameListActivity extends ListActivity {
26 | //public static final String SAVEGAME_DIR = "/data/data/com.tortuca.holokenmod/";
27 | public static final String SAVEGAME_AUTO_NAME = "autosave";
28 | public static final String SAVEGAME_NAME_PREFIX_ = "savegame_";
29 | public boolean mCurrentSaved;
30 | TextView empty;
31 | ListView saveGameList;
32 | ImageButton discardButton;
33 | private SaveGameListAdapter mAdapter;
34 |
35 | public SaveGameListActivity() {
36 | }
37 |
38 | @Override
39 | public void onCreate(Bundle savedInstanceState) {
40 | super.onCreate(savedInstanceState);
41 | if (!PreferenceManager.getDefaultSharedPreferences(this).getBoolean("showfullscreen", false))
42 | this.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
43 | else
44 | this.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
45 |
46 | setContentView(R.layout.activity_savegame);
47 | final Button saveButton =(Button) findViewById(R.id.savebutton);
48 | discardButton =(ImageButton) findViewById(R.id.discardbutton);
49 | empty = (TextView)findViewById(android.R.id.empty);
50 | saveGameList = (ListView) findViewById(android.R.id.list);
51 |
52 | String themePref = PreferenceManager.getDefaultSharedPreferences(this).getString("alternatetheme", "0");
53 | int theme = Integer.parseInt(themePref);
54 | this.findViewById(R.id.saveGameContainer).setBackgroundColor(
55 | MainActivity.BG_COLOURS[theme]);
56 | if (theme == GridView.THEME_LIGHT)
57 | saveButton.setTextColor(getResources().getColorStateList(R.color.text_button));
58 | else if (theme == GridView.THEME_DARK)
59 | saveButton.setTextColor(getResources().getColorStateList(R.color.text_button_dark));
60 |
61 | saveGameList.setEmptyView(empty);
62 | this.mAdapter = new SaveGameListAdapter(this);
63 | saveGameList.setAdapter(this.mAdapter);
64 |
65 | saveButton.setOnClickListener(new OnClickListener() {
66 | public void onClick(View v) {
67 | saveButton.setEnabled(false);
68 | currentSaveGame();
69 | }
70 | });
71 |
72 | if (this.mCurrentSaved)
73 | saveButton.setEnabled(false);
74 |
75 | discardButton.setEnabled(false);
76 | if (mAdapter.getCount() != 0)
77 | discardButton.setEnabled(true);
78 |
79 | discardButton.setOnClickListener(new OnClickListener() {
80 | public void onClick(View v) {
81 | deleteAllGamesDialog();
82 | }
83 | });
84 | }
85 |
86 | public void deleteSaveGame(final String filename) {
87 | new File(filename).delete();
88 | mAdapter.refreshFiles();
89 | mAdapter.notifyDataSetChanged();
90 | }
91 |
92 | public void deleteAllSaveGames() {
93 | File dir = this.getFilesDir();
94 | String[] allFiles = dir.list();
95 | for (String entryName : allFiles)
96 | if (entryName.startsWith("savegame_"))
97 | new File(dir + "/" + entryName).delete();
98 | mAdapter.refreshFiles();
99 | mAdapter.notifyDataSetChanged();
100 |
101 | discardButton.setEnabled(false);
102 | }
103 |
104 | public void deleteGameDialog(final String filename) {
105 | new AlertDialog.Builder(SaveGameListActivity.this)
106 | .setTitle(R.string.dialog_delete_title)
107 | .setMessage(R.string.dialog_delete_msg)
108 | .setNegativeButton(R.string.dialog_cancel, new DialogInterface.OnClickListener() {
109 | public void onClick(DialogInterface dialog, int whichButton) {
110 | dialog.cancel();
111 | }
112 | })
113 | .setPositiveButton(R.string.dialog_ok, new DialogInterface.OnClickListener() {
114 | public void onClick(DialogInterface dialog, int whichButton) {
115 | SaveGameListActivity.this.deleteSaveGame(filename);
116 | }
117 | })
118 | .show();
119 | }
120 |
121 | public void deleteAllGamesDialog() {
122 | new AlertDialog.Builder(SaveGameListActivity.this)
123 | .setTitle(R.string.dialog_delete_all_title)
124 | .setMessage(R.string.dialog_delete_all_msg)
125 | .setNegativeButton(R.string.dialog_cancel, new DialogInterface.OnClickListener() {
126 | public void onClick(DialogInterface dialog, int whichButton) {
127 | dialog.cancel();
128 | }
129 | })
130 | .setPositiveButton(R.string.dialog_ok, new DialogInterface.OnClickListener() {
131 | public void onClick(DialogInterface dialog, int whichButton) {
132 | SaveGameListActivity.this.deleteAllSaveGames();
133 | }
134 | })
135 | .show();
136 | }
137 |
138 | public void loadSaveGame(String filename) {
139 | Intent i = new Intent().putExtra("filename", filename);
140 | setResult(Activity.RESULT_OK, i);
141 | finish();
142 | }
143 |
144 | public void currentSaveGame() {
145 | this.mCurrentSaved = true;
146 | int fileIndex;
147 | File filename;
148 | for (fileIndex = 0 ; ; fileIndex++) {
149 | filename = new File(this.getFilesDir(), SAVEGAME_NAME_PREFIX_ + fileIndex);
150 | if (! filename.exists())
151 | break;
152 | }
153 | try {
154 | this.copy(new File(this.getFilesDir(),SAVEGAME_AUTO_NAME),filename);
155 | } catch (IOException e) {
156 | // TODO Auto-generated catch block
157 | e.printStackTrace();
158 | }
159 | this.mAdapter.refreshFiles();
160 | this.mAdapter.notifyDataSetChanged();
161 | }
162 |
163 |
164 | void copy(File src, File dst) throws IOException {
165 | InputStream in = new FileInputStream(src);
166 | OutputStream out = new FileOutputStream(dst);
167 |
168 | // Transfer bytes from in to out
169 | byte[] buf = new byte[1024];
170 | int len;
171 | while ((len = in.read(buf)) > 0) {
172 | out.write(buf, 0, len);
173 | }
174 | in.close();
175 | out.close();
176 | }
177 |
178 | }
179 |
--------------------------------------------------------------------------------
/app/src/main/res/layout-small/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
17 |
18 |
23 |
24 |
28 |
29 |
30 |
33 |
37 |
38 |
44 |
45 |
49 |
53 |
57 |
61 |
62 |
63 |
67 |
68 |
72 |
73 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
100 |
101 |
102 |
106 |
110 |
114 |
118 |
119 |
120 |
121 |
124 |
128 |
132 |
136 |
137 |
138 |
139 |
142 |
146 |
150 |
154 |
155 |
156 |
157 |
158 |
159 |
--------------------------------------------------------------------------------
/app/src/main/java/com/srlee/DLX/DLX.java:
--------------------------------------------------------------------------------
1 | package com.srlee.DLX;
2 |
3 | import java.util.ArrayList;
4 |
5 | public class DLX extends Object
6 | {
7 | public enum SolveType {ONE, MULTIPLE, ALL}
8 |
9 | private DLXColumn root = new DLXColumn();
10 | private DLXColumn[] ColHdrs;
11 | private DLXNode[] Nodes;
12 | private DLXRow[] Rows;
13 | private int numcols, numrows, numnodes;
14 | private DLXNode lastnodeadded;
15 | private ArrayList trysolution;
16 | private ArrayList foundsolution;
17 | private int NumSolns, NumAttempts;
18 | protected boolean isValid;
19 | private int prev_rowidx = -1;
20 | private SolveType solvetype;
21 |
22 | public DLX()
23 | {
24 | trysolution = new ArrayList();
25 | isValid = true;
26 | }
27 |
28 | public DLX(int nc, int nr, int nn)
29 | {
30 | Init(nc, nr, nn);
31 | }
32 |
33 | protected void Init(int nc, int nr, int nn)
34 | {
35 | numcols = nc;
36 | ColHdrs = new DLXColumn[numcols + 1];
37 | for (int c = 1; c <= numcols; c++)
38 | ColHdrs[c] = new DLXColumn();
39 |
40 | Nodes = new DLXNode[nn + 1];
41 | numnodes = 0; // None allocated
42 |
43 | Rows = new DLXRow[nr + 1];
44 | numrows = 0; // None allocated
45 |
46 | DLXColumn prev = root;
47 | for (int i = 1; i <= numcols; i++)
48 | {
49 | prev.SetRight(ColHdrs[i]);
50 | ColHdrs[i].SetLeft(prev);
51 | prev = ColHdrs[i];
52 | }
53 | root.SetLeft(ColHdrs[numcols]);
54 | ColHdrs[numcols].SetRight(root);
55 | }
56 | public int GetRowsInSolution() { return foundsolution.size(); }
57 | public int GetSolutionRow(int row)
58 | {
59 | return foundsolution.get(row - 1);
60 | }
61 | private void CoverCol(DLXColumn coverCol)
62 | {
63 | LL2DNode i, j;
64 | coverCol.GetRight().SetLeft(coverCol.GetLeft());
65 | coverCol.GetLeft().SetRight(coverCol.GetRight());
66 |
67 | i = coverCol.GetDown();
68 | while (i != coverCol)
69 | {
70 | j = i.GetRight();
71 | while (j != i)
72 | {
73 | j.GetDown().SetUp(j.GetUp());
74 | j.GetUp().SetDown(j.GetDown());
75 | ((DLXNode)j).GetColumn().DecSize();
76 | j = j.GetRight();
77 | }
78 | i = i.GetDown();
79 | }
80 | }
81 | private void UncoverCol(DLXColumn uncoverCol)
82 | {
83 | LL2DNode i, j;
84 |
85 | i = uncoverCol.GetUp();
86 | while (i != uncoverCol)
87 | {
88 | j = i.GetLeft();
89 | while (j != i)
90 | {
91 | ((DLXNode)j).GetColumn().IncSize();
92 | j.GetDown().SetUp(j);
93 | j.GetUp().SetDown(j);
94 | j = j.GetLeft();
95 | }
96 | i = i.GetUp();
97 | }
98 | uncoverCol.GetRight().SetLeft(uncoverCol);
99 | uncoverCol.GetLeft().SetRight(uncoverCol);
100 | }
101 | private DLXColumn ChooseMinCol()
102 | {
103 | int minsize = Integer.MAX_VALUE;
104 | DLXColumn search, mincol;
105 | int colNum = 0;
106 |
107 | mincol = search = (DLXColumn)root.GetRight();
108 |
109 | while (search != root)
110 | {
111 | if (search.GetSize() < minsize)
112 | {
113 | mincol = search;
114 | minsize = mincol.GetSize();
115 | if (minsize == 0)
116 | {
117 | break;
118 | }
119 | }
120 | search = (DLXColumn)search.GetRight();
121 | ++colNum;
122 | }
123 | if (minsize==0)
124 | return null;
125 | else
126 | return mincol;
127 | }
128 |
129 | public void AddNode(int colidx, int rowidx)
130 | {
131 | Nodes[++numnodes] = new DLXNode(ColHdrs[colidx], rowidx);
132 | if (prev_rowidx == rowidx)
133 | {
134 | Nodes[numnodes].SetLeft(lastnodeadded);
135 | Nodes[numnodes].SetRight(lastnodeadded.GetRight());
136 | lastnodeadded.SetRight(Nodes[numnodes]);
137 | Nodes[numnodes].GetRight().SetLeft(Nodes[numnodes]);
138 | }
139 | else
140 | {
141 | prev_rowidx = rowidx;
142 | Rows[++numrows] = new DLXRow(Nodes[numnodes]);
143 | Nodes[numnodes].SetLeft(Nodes[numnodes]);
144 | Nodes[numnodes].SetRight(Nodes[numnodes]);
145 | }
146 | lastnodeadded = Nodes[numnodes];
147 | }
148 |
149 | public boolean GivenRow(int row)
150 | {
151 | return Given(Rows[row].FirstNode);
152 | }
153 |
154 | public boolean Given(DLXNode node)
155 | {
156 | DLXNode startNode = node;
157 | DLXNode currNode = startNode;
158 | do
159 | {
160 | DLXColumn ColHdr = currNode.GetColumn();
161 | // Check if this is still a valid column
162 | if (ColHdr.GetLeft().GetRight() != ColHdr)
163 | return false;
164 | CoverCol(ColHdr);
165 | currNode = (DLXNode)currNode.GetRight();
166 | } while (currNode != startNode);
167 | int i = currNode.GetRowIdx();
168 | trysolution.add(i);
169 | return true;
170 | }
171 |
172 | public boolean Given(int node)
173 | {
174 | return Given(Nodes[node]);
175 | }
176 |
177 | public int Solve(SolveType st)
178 | {
179 | if (!isValid)
180 | return -1;
181 |
182 | solvetype = st;
183 | NumSolns = 0;
184 | NumAttempts = 0;
185 | search(trysolution.size());
186 | return NumSolns;
187 | }
188 |
189 | private void search(int k)
190 | {
191 | DLXColumn chosenCol;
192 | LL2DNode r, j;
193 |
194 | if (root.GetRight() == root)
195 | {
196 | foundsolution = new ArrayList(trysolution);
197 | NumSolns++;
198 | return;
199 | }
200 | chosenCol = ChooseMinCol();
201 | if (chosenCol != null) {
202 | CoverCol(chosenCol);
203 | r = chosenCol.GetDown();
204 |
205 | while (r != chosenCol)
206 | {
207 | if (k >= trysolution.size())
208 | trysolution.add(((DLXNode)r).GetRowIdx());
209 | else
210 | trysolution.set(k, ((DLXNode)r).GetRowIdx());
211 | NumAttempts++;
212 | j = r.GetRight();
213 | while (j != r)
214 | {
215 | CoverCol(((DLXNode)j).GetColumn());
216 | j = j.GetRight();
217 | }
218 | search(k + 1);
219 | if (solvetype == SolveType.ONE && NumSolns > 0) // Stop as soon as we find 1 solution
220 | return;
221 | if (solvetype == SolveType.MULTIPLE && NumSolns > 1) // Stop as soon as we find multiple solutions
222 | return;
223 | j = r.GetLeft();
224 | while (j != r)
225 | {
226 | UncoverCol(((DLXNode)j).GetColumn());
227 | j = j.GetLeft();
228 | }
229 | r = r.GetDown();
230 | }
231 | UncoverCol(chosenCol);
232 | }
233 | return;
234 | }
235 | }
236 |
--------------------------------------------------------------------------------
/app/src/main/res/layout-sw480dp-land/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
14 |
15 |
19 |
20 |
30 |
31 |
33 |
34 |
37 |
38 |
39 |
40 |
41 |
42 |
46 |
47 |
54 |
55 |
62 |
63 |
69 |
73 |
74 |
75 |
83 |
84 |
85 |
88 |
91 |
94 |
95 |
96 |
97 |
100 |
103 |
106 |
107 |
108 |
109 |
112 |
115 |
118 |
119 |
120 |
123 |
126 |
129 |
130 |
131 |
132 |
137 |
138 |
142 |
146 |
150 |
154 |
155 |
156 |
157 |
158 |
159 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_stats.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
14 |
15 |
18 |
19 |
22 |
23 |
28 |
31 |
32 |
33 |
34 |
39 |
42 |
43 |
44 |
45 |
50 |
53 |
54 |
55 |
56 |
60 |
63 |
64 |
65 |
66 |
70 |
73 |
74 |
75 |
76 |
77 |
81 |
82 |
87 |
88 |
89 |
94 |
98 |
99 |
100 |
105 |
109 |
110 |
111 |
116 |
120 |
121 |
122 |
127 |
131 |
132 |
133 |
138 |
142 |
143 |
144 |
149 |
153 |
154 |
155 |
156 |
160 |
161 |
162 |
--------------------------------------------------------------------------------
/app/src/main/java/com/holokenmod/SaveGame.java:
--------------------------------------------------------------------------------
1 | package com.holokenmod;
2 |
3 | import android.content.Context;
4 | import android.util.Log;
5 |
6 | import java.io.BufferedReader;
7 | import java.io.BufferedWriter;
8 | import java.io.File;
9 | import java.io.FileInputStream;
10 | import java.io.FileNotFoundException;
11 | import java.io.FileWriter;
12 | import java.io.IOException;
13 | import java.io.InputStream;
14 | import java.io.InputStreamReader;
15 | import java.util.ArrayList;
16 |
17 | public class SaveGame {
18 | private Context context;
19 | public File filename;
20 |
21 | public SaveGame(Context context) {
22 | this.context=context;
23 | this.filename = getAutosave();
24 | }
25 | public SaveGame(String filename) {
26 | this.filename = new File(filename);
27 |
28 | }
29 |
30 |
31 | public boolean Save(GridView view) {
32 | synchronized (view.mLock) { // Avoid saving game at the same time as creating puzzle
33 | BufferedWriter writer = null;
34 | try {
35 | writer = new BufferedWriter(new FileWriter(this.filename));
36 | long now = System.currentTimeMillis();
37 | writer.write(now + "\n");
38 | writer.write(view.mGridSize + "\n");
39 | writer.write(view.mPlayTime +"\n");
40 | writer.write(view.mActive + "\n");
41 | for (GridCell cell : view.mCells) {
42 | writer.write("CELL:");
43 | writer.write(cell.mCellNumber + ":");
44 | writer.write(cell.mRow + ":");
45 | writer.write(cell.mColumn + ":");
46 | writer.write(cell.mCageText + ":");
47 | writer.write(cell.mValue + ":");
48 | writer.write(cell.getUserValue() + ":");
49 | for (int possible : cell.mPossibles)
50 | writer.write(possible + ",");
51 | writer.write("\n");
52 | }
53 | if (view.mSelectedCell != null)
54 | writer.write("SELECTED:" + view.mSelectedCell.mCellNumber + "\n");
55 | ArrayList invalidchoices = view.invalidsHighlighted();
56 | if (invalidchoices.size() > 0) {
57 | writer.write("INVALID:");
58 | for (GridCell cell : invalidchoices)
59 | writer.write(cell.mCellNumber + ",");
60 | writer.write("\n");
61 | }
62 | ArrayList cheatedcells = view.cheatedHighlighted();
63 | if (cheatedcells.size() > 0) {
64 | writer.write("CHEATED:");
65 | for (GridCell cell : cheatedcells)
66 | writer.write(cell.mCellNumber + ",");
67 | writer.write("\n");
68 | }
69 | for (GridCage cage : view.mCages) {
70 | writer.write("CAGE:");
71 | writer.write(cage.mId + ":");
72 | writer.write(cage.mAction + ":");
73 | writer.write(cage.mActionStr + ":");
74 | writer.write(cage.mResult + ":");
75 | writer.write(cage.mType + ":");
76 | for (GridCell cell : cage.mCells)
77 | writer.write(cell.mCellNumber + ",");
78 | //writer.write(":" + cage.isOperatorHidden());
79 | writer.write("\n");
80 | }
81 | }
82 | catch (IOException e) {
83 | Log.d("HoloKen", "Error saving game: "+e.getMessage());
84 | return false;
85 | }
86 | finally {
87 | try {
88 | if (writer != null)
89 | writer.close();
90 | } catch (IOException e) {
91 | //pass
92 | return false;
93 | }
94 | }
95 | } // End of synchronised block
96 | Log.d("MathDoku", "Saved game.");
97 | return true;
98 | }
99 |
100 |
101 | public long ReadDate() {
102 | BufferedReader br = null;
103 | InputStream ins = null;
104 | try {
105 | ins = new FileInputStream((this.filename));
106 | br = new BufferedReader(new InputStreamReader(ins), 8192);
107 | return Long.parseLong(br.readLine());
108 | } catch (FileNotFoundException e) {
109 | // TODO Auto-generated catch block
110 | e.printStackTrace();
111 | } catch (NumberFormatException e) {
112 | // TODO Auto-generated catch block
113 | e.printStackTrace();
114 | } catch (IOException e) {
115 | // TODO Auto-generated catch block
116 | e.printStackTrace();
117 | }
118 | finally {
119 | try {
120 | ins.close();
121 | br.close();
122 | } catch (Exception e) {
123 | // Nothing.
124 | return 0;
125 | }
126 | }
127 | return 0;
128 | }
129 |
130 | public boolean Restore(GridView view) {
131 | String line = null;
132 | BufferedReader br = null;
133 | InputStream ins = null;
134 | String[] cellParts;
135 | String[] cageParts;
136 | try {
137 | ins = new FileInputStream((this.filename));
138 | br = new BufferedReader(new InputStreamReader(ins), 8192);
139 | view.mDate = Long.parseLong(br.readLine());
140 | view.mGridSize = Integer.parseInt(br.readLine());
141 | view.mPlayTime = Long.parseLong(br.readLine());
142 | view.mActive = br.readLine().equals("true");
143 | view.mCells = new ArrayList();
144 | while ((line = br.readLine()) != null) {
145 | if (!line.startsWith("CELL:")) break;
146 | cellParts = line.split(":");
147 | int cellNum = Integer.parseInt(cellParts[1]);
148 | GridCell cell = new GridCell(view, cellNum);
149 | cell.mRow = Integer.parseInt(cellParts[2]);
150 | cell.mColumn = Integer.parseInt(cellParts[3]);
151 | cell.mCageText = cellParts[4];
152 | cell.mValue = Integer.parseInt(cellParts[5]);
153 | cell.setUserValue(Integer.parseInt(cellParts[6]));
154 | if (cellParts.length == 8)
155 | for (String possible : cellParts[7].split(","))
156 | cell.mPossibles.add(Integer.parseInt(possible));
157 | view.mCells.add(cell);
158 | }
159 | view.mSelectedCell = null;
160 | if (line.startsWith("SELECTED:")) {
161 | int selected = Integer.parseInt(line.split(":")[1]);
162 | view.mSelectedCell = view.mCells.get(selected);
163 | view.mSelectedCell.mSelected = true;
164 | line = br.readLine();
165 | }
166 | if (line.startsWith("INVALID:")) {
167 | String invalidlist = line.split(":")[1];
168 | for (String cellId : invalidlist.split(",")) {
169 | int cellNum = Integer.parseInt(cellId);
170 | GridCell c = view.mCells.get(cellNum);
171 | c.setInvalidHighlight(true);
172 | }
173 | line = br.readLine();
174 | }
175 | if (line.startsWith("CHEATED")) {
176 | String cheatedlist = line.split(":")[1];
177 | for (String cellId : cheatedlist.split(",")) {
178 | int cellNum = Integer.parseInt(cellId);
179 | GridCell c = view.mCells.get(cellNum);
180 | c.setCheatedHighlight(true);
181 | }
182 | line = br.readLine();
183 | }
184 | view.mCages = new ArrayList();
185 | do {
186 | cageParts = line.split(":");
187 | GridCage cage;
188 | cage = new GridCage(view, Integer.parseInt(cageParts[5]));
189 | cage.mId = Integer.parseInt(cageParts[1]);
190 | cage.mAction = Integer.parseInt(cageParts[2]);
191 | cage.mActionStr = cageParts[3];
192 | cage.mResult = Integer.parseInt(cageParts[4]);
193 | for (String cellId : cageParts[6].split(",")) {
194 | int cellNum = Integer.parseInt(cellId);
195 | GridCell c = view.mCells.get(cellNum);
196 | c.mCageId = cage.mId;
197 | cage.mCells.add(c);
198 | }
199 | view.mCages.add(cage);
200 | } while ((line = br.readLine()) != null);
201 |
202 | } catch (FileNotFoundException e) {
203 | Log.d("Mathdoku", "FNF Error restoring game: " + e.getMessage());
204 | return false;
205 | } catch (IOException e) {
206 | Log.d("Mathdoku", "IO Error restoring game: " + e.getMessage());
207 | return false;
208 | }
209 | finally {
210 | try {
211 | ins.close();
212 | br.close();
213 | if (this.filename.getCanonicalPath().equals(getAutosave()))
214 | (filename).delete();
215 | } catch (Exception e) {
216 | // Nothing.
217 | return false;
218 | }
219 | }
220 | return true;
221 | }
222 |
223 | public File getAutosave() {
224 | return new File(context.getFilesDir(), SaveGameListActivity.SAVEGAME_AUTO_NAME);
225 | }
226 |
227 |
228 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/mobiRic/ui/widget/Boast.java:
--------------------------------------------------------------------------------
1 | package com.mobiRic.ui.widget;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.content.Context;
5 | import android.content.res.Resources;
6 | import android.widget.Toast;
7 |
8 | /**
9 | * {@link Toast} decorator allowing for easy cancellation of notifications. Use
10 | * this class if you want subsequent Toast notifications to overwrite current
11 | * ones.
12 | *
13 | * By default, a current {@link Boast} notification will be cancelled by a
14 | * subsequent notification. This default behaviour can be changed by calling
15 | * certain methods like {@link #show(boolean)}.
16 | */
17 | public class Boast
18 | {
19 | /**
20 | * Keeps track of certain {@link Boast} notifications that may need to be cancelled.
21 | * This functionality is only offered by some of the methods in this class.
22 | */
23 | private volatile static Boast globalBoast = null;
24 |
25 | // ////////////////////////////////////////////////////////////////////////////////////////////////////////
26 |
27 | /**
28 | * Internal reference to the {@link Toast} object that will be displayed.
29 | */
30 | private Toast internalToast;
31 |
32 | // ////////////////////////////////////////////////////////////////////////////////////////////////////////
33 |
34 | /**
35 | * Private constructor creates a new {@link Boast} from a given
36 | * {@link Toast}.
37 | *
38 | * @throws NullPointerException
39 | * if the parameter is null.
40 | */
41 | private Boast(Toast toast)
42 | {
43 | // null check
44 | if (toast == null)
45 | {
46 | throw new NullPointerException(
47 | "Boast.Boast(Toast) requires a non-null parameter.");
48 | }
49 |
50 | internalToast = toast;
51 | }
52 |
53 | // ////////////////////////////////////////////////////////////////////////////////////////////////////////
54 |
55 | /**
56 | * Make a standard {@link Boast} that just contains a text view.
57 | *
58 | * @param context
59 | * The context to use. Usually your {@link android.app.Application}
60 | * or {@link android.app.Activity} object.
61 | * @param text
62 | * The text to show. Can be formatted text.
63 | * @param duration
64 | * How long to display the message. Either {@link Toast#LENGTH_SHORT} or
65 | * {@link Toast#LENGTH_LONG}
66 | */
67 | @SuppressLint("ShowToast")
68 | public static Boast makeText(Context context, CharSequence text,
69 | int duration)
70 | {
71 | return new Boast(Toast.makeText(context, text, duration));
72 | }
73 |
74 | /**
75 | * Make a standard {@link Boast} that just contains a text view with the
76 | * text from a resource.
77 | *
78 | * @param context
79 | * The context to use. Usually your {@link android.app.Application}
80 | * or {@link android.app.Activity} object.
81 | * @param resId
82 | * The resource id of the string resource to use. Can be formatted
83 | * text.
84 | * @param duration
85 | * How long to display the message. Either {@link Toast#LENGTH_SHORT} or
86 | * {@link Toast#LENGTH_LONG}
87 | *
88 | * @throws Resources.NotFoundException
89 | * if the resource can't be found.
90 | */
91 | @SuppressLint("ShowToast")
92 | public static Boast makeText(Context context, int resId, int duration)
93 | throws Resources.NotFoundException
94 | {
95 | return new Boast(Toast.makeText(context, resId, duration));
96 | }
97 |
98 | /**
99 | * Make a standard {@link Boast} that just contains a text view. Duration
100 | * defaults to {@link Toast#LENGTH_SHORT}.
101 | *
102 | * @param context
103 | * The context to use. Usually your {@link android.app.Application}
104 | * or {@link android.app.Activity} object.
105 | * @param text
106 | * The text to show. Can be formatted text.
107 | */
108 | @SuppressLint("ShowToast")
109 | public static Boast makeText(Context context, CharSequence text)
110 | {
111 | return new Boast(Toast.makeText(context, text, Toast.LENGTH_SHORT));
112 | }
113 |
114 | /**
115 | * Make a standard {@link Boast} that just contains a text view with the
116 | * text from a resource. Duration defaults to {@link Toast#LENGTH_SHORT}.
117 | *
118 | * @param context
119 | * The context to use. Usually your {@link android.app.Application}
120 | * or {@link android.app.Activity} object.
121 | * @param resId
122 | * The resource id of the string resource to use. Can be formatted
123 | * text.
124 | *
125 | * @throws Resources.NotFoundException
126 | * if the resource can't be found.
127 | */
128 | @SuppressLint("ShowToast")
129 | public static Boast makeText(Context context, int resId)
130 | throws Resources.NotFoundException
131 | {
132 | return new Boast(Toast.makeText(context, resId, Toast.LENGTH_SHORT));
133 | }
134 |
135 | // ////////////////////////////////////////////////////////////////////////////////////////////////////////
136 |
137 | /**
138 | * Show a standard {@link Boast} that just contains a text view.
139 | *
140 | * @param context
141 | * The context to use. Usually your {@link android.app.Application}
142 | * or {@link android.app.Activity} object.
143 | * @param text
144 | * The text to show. Can be formatted text.
145 | * @param duration
146 | * How long to display the message. Either {@link Toast#LENGTH_SHORT} or
147 | * {@link Toast#LENGTH_LONG}
148 | */
149 | public static void showText(Context context, CharSequence text, int duration)
150 | {
151 | Boast.makeText(context, text, duration).show();
152 | }
153 |
154 | /**
155 | * Show a standard {@link Boast} that just contains a text view with the
156 | * text from a resource.
157 | *
158 | * @param context
159 | * The context to use. Usually your {@link android.app.Application}
160 | * or {@link android.app.Activity} object.
161 | * @param resId
162 | * The resource id of the string resource to use. Can be formatted
163 | * text.
164 | * @param duration
165 | * How long to display the message. Either {@link Toast#LENGTH_SHORT} or
166 | * {@link Toast#LENGTH_LONG}
167 | *
168 | * @throws Resources.NotFoundException
169 | * if the resource can't be found.
170 | */
171 | public static void showText(Context context, int resId, int duration)
172 | throws Resources.NotFoundException
173 | {
174 | Boast.makeText(context, resId, duration).show();
175 | }
176 |
177 | /**
178 | * Show a standard {@link Boast} that just contains a text view. Duration
179 | * defaults to {@link Toast#LENGTH_SHORT}.
180 | *
181 | * @param context
182 | * The context to use. Usually your {@link android.app.Application}
183 | * or {@link android.app.Activity} object.
184 | * @param text
185 | * The text to show. Can be formatted text.
186 | */
187 | public static void showText(Context context, CharSequence text)
188 | {
189 | Boast.makeText(context, text, Toast.LENGTH_SHORT).show();
190 | }
191 |
192 | /**
193 | * Show a standard {@link Boast} that just contains a text view with the
194 | * text from a resource. Duration defaults to {@link Toast#LENGTH_SHORT}.
195 | *
196 | * @param context
197 | * The context to use. Usually your {@link android.app.Application}
198 | * or {@link android.app.Activity} object.
199 | * @param resId
200 | * The resource id of the string resource to use. Can be formatted
201 | * text.
202 | *
203 | * @throws Resources.NotFoundException
204 | * if the resource can't be found.
205 | */
206 | public static void showText(Context context, int resId)
207 | throws Resources.NotFoundException
208 | {
209 | Boast.makeText(context, resId, Toast.LENGTH_SHORT).show();
210 | }
211 |
212 | // ////////////////////////////////////////////////////////////////////////////////////////////////////////
213 |
214 | /**
215 | * Close the view if it's showing, or don't show it if it isn't showing yet.
216 | * You do not normally have to call this. Normally view will disappear on
217 | * its own after the appropriate duration.
218 | */
219 | public void cancel()
220 | {
221 | internalToast.cancel();
222 | }
223 |
224 | /**
225 | * Show the view for the specified duration. By default, this method cancels
226 | * any current notification to immediately display the new one. For
227 | * conventional {@link Toast#show()} queueing behaviour, use method
228 | * {@link #show(boolean)}.
229 | *
230 | * @see #show(boolean)
231 | */
232 | public void show()
233 | {
234 | show(true);
235 | }
236 |
237 | /**
238 | * Show the view for the specified duration. This method can be used to
239 | * cancel the current notification, or to queue up notifications.
240 | *
241 | * @param cancelCurrent
242 | * true to cancel any current notification and replace
243 | * it with this new one
244 | *
245 | * @see #show()
246 | */
247 | public void show(boolean cancelCurrent)
248 | {
249 | // cancel current
250 | if (cancelCurrent && (globalBoast != null))
251 | {
252 | globalBoast.cancel();
253 | }
254 |
255 | // save an instance of this current notification
256 | globalBoast = this;
257 |
258 | internalToast.show();
259 | }
260 |
261 | }
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | HoloKenMod
4 |
5 | New Game
6 | Save/Load
7 | Restart Game
8 | Share puzzle
9 | Statistics
10 | Settings
11 | Help
12 |
13 | Show mistakes
14 | Reveal cell
15 | Reveal cage
16 | Show solution
17 |
18 | 4x4 (Easy)
19 | 5x5 (Medium)
20 | 6x6 (Hard)
21 | 7x7 (Harder)
22 | 8x8 (Hardest)
23 | 9x9 (Ultimate)
24 |
25 | 1
26 | 2
27 | 3
28 | 4
29 | 5
30 | 6
31 | 7
32 | 8
33 | 9
34 |
35 | Pen
36 | Pencil
37 | Eraser
38 |
39 | Load game
40 | Delete game
41 |
42 | Show operators
43 | All mathematical operations
44 | Addition and subtraction
45 | Addition and multiplication
46 | Multiplication only
47 |
48 | Puzzle solved!
49 | New best time -
50 | Time -
51 | Saving screenshot to
52 |
53 | 00:00:00
54 | Save current game
55 | No save games found
56 |
57 |
58 | Puzzle Generation
59 | Default game grid
60 | Set the grid size for new games
61 | Default operations
62 | Choose arithmetic modes of operation
63 | Default operator display
64 | Choose display of operators (+, -, *, /)
65 |
66 | Game Assistance
67 | Highlight incorrect maths
68 | Highlight duplicates
69 | Auto-remove pencil marks
70 | In the same row or column as a penned number
71 |
72 | Display
73 | Theme
74 | Pencil marks at game start
75 | Pencil marks in 3x3 grid
76 | Show in 3x3 grid
77 | Show in numerical order instead
78 | Show game timer
79 | Show full screen
80 | Keep screen on
81 |
82 | HoloKen
83 | Rate HoloKen
84 | Rate HoloKen in the Google Play Store
85 | Any bugs or suggested features?
86 | Click here to report them online
87 |
88 | Statistics
89 | Puzzle Statistics
90 | Times - Best // Average
91 | Puzzles started
92 | Puzzles hinted
93 | Puzzles solved
94 | Current streak
95 | Longest streak
96 | Reset statistics
97 |
98 |
99 | Help
100 | Rules
101 |
102 | Fill in each row and column with numbers from 1 to grid size (4-9).
103 | Numbers may only be used once per row and column.\n\n
104 | Thick lines indicate \'cages\', where each cage has a math puzzle to be solved.
105 | For example, \'5+\' means all numbers in that cage must add up to 5.\n\n
106 | Numbers may be used more than once per cage, as long as there is only one of each number per row or column.
107 |
108 | How to play
109 |
110 | Fill up the grid squares using the number buttons.
111 | Toggle between pen, pencil and eraser modes to mark or clear possibilities.
112 | Quick toggle between input modes - select cell first or select number first.\n\n
113 | Long-press a cell for more hints (show mistakes, reveal cell, show solution).\n
114 | ^ warning: use of hints will add a time penalty and break your current streak\n\n
115 | Long-press the Pen/Pencil button to quickly pen in all singular Pencil marks.\n\n
116 | HoloKen will auto-save your game if you need to stop.
117 |
118 |
119 | About
120 | Version
121 | HoloKenMod 1.6.1
122 | License
123 | GNU General Public License v3
124 | Project Home
125 | Report any bugs or suggestions at\nhttps://github.com/queler/holokenmod
126 | Developer
127 | Adam Queler, Forked from Holoken 1.1.1 by Amanda Chow, with much credit to Ben Buxton and Stephen Lee of Mathdoku
128 | Changelog
129 |
130 | v1.6.1 merged pencil mark option, infinite undo buffer\n
131 | v1.5.1 all autofill is recursive\n
132 | v1.4.1 fixed more serious lint errors\n
133 | v1.4 Fixed toasts, changed defaults to holodark and auto-remove\n
134 | migrated to gradle\n
135 | fixed crash when error and holding pencil\n
136 | v1.3 Forked from 1.1.1 on googlecode\n
137 | Incorporated 1.2 once I found it on github\n
138 | auto-pencil marks (needs option to turn off)\n
139 | better colors for Dark mode\n
140 | clearing single possibilites will remove pencil marks now…\n
141 | …but will crash eventually if there\'s a mistake\n
142 | v1.2 (I think I merged these in)\n
143 | * Coloured last modified cell\n
144 | * Centered options menu to work for 3.0 devices\n
145 | * Tweaked 480dp layout\n
146 | * Added operations menu\n
147 | v1.1.1\n * Fixed slight border bug\n
148 | v1.1\n * Shows streaks and average times in statistics\n
149 | * Changed time penalty\n
150 | * Added input mode, batch undo fixes\n
151 | * Auto-remove pencil marks, fix layout bug\n
152 | v1.0.3\n * Theme tweaks and multiple undo\n
153 | v1.0\n * Initial release
154 |
155 |
156 | OK
157 | Cancel
158 |
159 | Generating puzzle…
160 |
161 | Restart game?
162 | This game will be restarted
163 |
164 | Delete game?
165 | This game will be deleted
166 |
167 | Delete all games?
168 | All games will be deleted
169 |
170 | This puzzle is hard eh
171 |
172 | - 1 mistake /
173 | - %d mistakes /
174 |
175 |
176 | - 1 filled cell
177 | - %d filled cells
178 |
179 |
180 |
181 |
--------------------------------------------------------------------------------
/app/src/main/java/com/holokenmod/GridCell.java:
--------------------------------------------------------------------------------
1 | package com.holokenmod;
2 |
3 | import android.app.Activity;
4 | import android.content.SharedPreferences;
5 | import android.graphics.Canvas;
6 | import android.graphics.Paint;
7 | import android.preference.PreferenceManager;
8 |
9 | import java.util.ArrayList;
10 | import java.util.Collections;
11 | import java.util.List;
12 |
13 | public class GridCell {
14 | // Index of the cell (left to right, top to bottom, zero-indexed)
15 | public int mCellNumber;
16 | // X grid position, zero indexed
17 | public int mColumn;
18 | // Y grid position, zero indexed
19 | public int mRow;
20 | // X pixel position
21 | public float mPosX;
22 | // Y pixel position
23 | public float mPosY;
24 | // Value of the digit in the cell
25 | public int mValue;
26 | // User's entered value
27 | public int mUserValue;
28 | // Id of the enclosing cage
29 | public int mCageId;
30 | // String of the cage
31 | public String mCageText;
32 | // View context
33 | public GridView mContext;
34 | // User's candidate digits
35 | public List mPossibles;
36 | // Whether to show warning background (duplicate value in row/col)
37 | public boolean mShowWarning;
38 | // Whether to show cell as selected
39 | public boolean mSelected;
40 | // Player cheated (revealed this cell)
41 | public boolean mCheated;
42 | // Cell was the last touched
43 | public boolean mLastModified;
44 |
45 | // Highlight user input isn't correct value
46 | private boolean mInvalidHighlight;
47 |
48 | public static final int BORDER_NONE = 0;
49 | public static final int BORDER_SOLID = 1;
50 | public static final int BORDER_WARN = 3;
51 | public static final int BORDER_CAGE_SELECTED = 4;
52 |
53 | public static final int NORTH = 0;
54 | public static final int EAST = 1;
55 | public static final int SOUTH = 2;
56 | public static final int WEST = 3;
57 |
58 |
59 | public int[] mBorderTypes;
60 |
61 |
62 | private Paint mValuePaint;
63 | private Paint mBorderPaint;
64 | private Paint mCageSelectedPaint;
65 |
66 | private Paint mWrongBorderPaint;
67 | private Paint mCageTextPaint;
68 | private Paint mPossiblesPaint;
69 | private Paint mWarningPaint;
70 | private Paint mCheatedPaint;
71 | private Paint mSelectedPaint;
72 | private Paint mUserSetPaint;
73 | private Paint mLastModifiedPaint;
74 |
75 | public int mTheme;
76 |
77 | public GridCell(GridView context, int cell) {
78 | int gridSize = context.mGridSize;
79 | this.mContext = context;
80 | this.mCellNumber = cell;
81 | this.mColumn = cell % gridSize;
82 | this.mRow = cell / gridSize;
83 | this.mCageText = "";
84 | this.mCageId = -1;
85 | this.mValue = 0;
86 | this.mUserValue = 0;
87 | this.mShowWarning = false;
88 | this.mCheated = false;
89 | this.mLastModified = false;
90 | this.mInvalidHighlight = false;
91 |
92 | this.mPosX = 0;
93 | this.mPosY = 0;
94 |
95 | this.mBorderPaint = new Paint();
96 | this.mBorderPaint.setColor(0xFF000000);
97 | this.mBorderPaint.setStrokeWidth(2);
98 |
99 | this.mCageSelectedPaint = new Paint();
100 | this.mCageSelectedPaint.setColor(0xFF000000);
101 | this.mCageSelectedPaint.setStrokeWidth(4);
102 |
103 | this.mWrongBorderPaint = new Paint();
104 | this.mWrongBorderPaint.setColor(0xFFcc0000);
105 | this.mWrongBorderPaint.setStrokeWidth(3);
106 |
107 | this.mUserSetPaint = new Paint();
108 | this.mWarningPaint = new Paint();
109 | this.mCheatedPaint = new Paint();
110 | this.mSelectedPaint = new Paint();
111 | this.mLastModifiedPaint = new Paint();
112 |
113 | this.mUserSetPaint.setColor(0xFFFFFFFF); //white
114 | this.mWarningPaint.setColor(0x90ff4444); //red
115 | this.mCheatedPaint.setColor(0x99d6b4e6); //purple
116 | this.mSelectedPaint.setColor(0xFFffaa33); //orange
117 | this.mLastModifiedPaint.setColor(0x44eeff33); //yellow
118 |
119 | this.mCageTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
120 | this.mCageTextPaint.setColor(0xFF33b5e5);
121 | this.mCageTextPaint.setTextSize(14);
122 |
123 | this.mValuePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
124 | this.mValuePaint.setColor(0xFF000000);
125 |
126 | this.mPossiblesPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
127 | this.mPossiblesPaint.setColor(0xFF000000);
128 | this.mPossiblesPaint.setTextSize(10);
129 |
130 | this.mPossibles = Collections.synchronizedList( new ArrayList());
131 |
132 | this.setBorders(BORDER_NONE, BORDER_NONE, BORDER_NONE, BORDER_NONE);
133 | }
134 |
135 | public void setTheme(int theme) {
136 | this.mTheme = theme;
137 | if (theme == GridView.THEME_LIGHT) {
138 | this.mUserSetPaint.setColor(0xFFFFFFFF);
139 | this.mBorderPaint.setColor(0xFF000000);
140 | this.mCageSelectedPaint.setColor(0xFF000000);
141 | this.mValuePaint.setColor(0xFF000000);
142 | this.mPossiblesPaint.setColor(0xFF000000);
143 | this.mCageTextPaint.setColor(0xFF0086B3);
144 | }
145 | else if (theme == GridView.THEME_DARK) {
146 | this.mUserSetPaint.setColor(0xFF000000);
147 | this.mBorderPaint.setColor(0xFFFFFFFF);
148 | this.mCageSelectedPaint.setColor(0xFFFFFFFF);
149 | this.mValuePaint.setColor(0xFFFFFFFF);
150 | this.mPossiblesPaint.setColor(0xFFFFFFFF);
151 | this.mCageTextPaint.setColor(0xFF33b5e5);
152 | }
153 |
154 | /*if (this.mContext.getMeasuredHeight() < 150) {
155 | this.mBorderPaint.setStrokeWidth(1);
156 | this.mCageSelectedPaint.setStrokeWidth(2);
157 | this.mWrongBorderPaint.setStrokeWidth(2);
158 | }*/
159 | }
160 |
161 | public String toString() {
162 | String str = "";
165 | return str;
166 | }
167 |
168 | /* Sets the cells border type to the given values.
169 | *
170 | * Border is BORDER_NONE, BORDER_SOLID, BORDER_WARN or BORDER_CAGE_SELECTED.
171 | */
172 | public void setBorders(int north, int east, int south, int west) {
173 | int[] borders = new int[4];
174 | borders[NORTH] = north;
175 | borders[EAST] = east;
176 | borders[SOUTH] = south;
177 | borders[WEST] = west;
178 | this.mBorderTypes = borders;
179 | }
180 |
181 | /* Returns the Paint object for the given border of this cell. */
182 | private Paint getBorderPaint(int border) {
183 | switch (this.mBorderTypes[border]) {
184 | case BORDER_NONE:
185 | return null;
186 | case BORDER_SOLID :
187 | return this.mBorderPaint;
188 | case BORDER_WARN :
189 | return this.mWrongBorderPaint;
190 | case BORDER_CAGE_SELECTED :
191 | return this.mCageSelectedPaint;
192 | }
193 | return null;
194 | }
195 |
196 | public void togglePossible(int digit) {
197 | if (this.mPossibles.indexOf(Integer.valueOf(digit)) == -1)
198 | this.mPossibles.add(digit);
199 | else
200 | this.mPossibles.remove(Integer.valueOf(digit));
201 | Collections.sort(mPossibles);
202 | }
203 |
204 | public boolean isPossible(int digit) {
205 | return this.mPossibles.indexOf(Integer.valueOf(digit)) != -1;
206 | }
207 |
208 | public synchronized void removePossible(int digit) {
209 | if (this.mPossibles.indexOf(Integer.valueOf(digit)) != -1)
210 | this.mPossibles.remove(Integer.valueOf(digit));
211 | Collections.sort(mPossibles);
212 | }
213 |
214 | public void toggleUserValue(){
215 | int x = getUserValue();
216 | clearUserValue();
217 | togglePossible(x);
218 | }
219 |
220 | public int getUserValue() {
221 | return mUserValue;
222 | }
223 |
224 | public boolean isUserValueSet() {
225 | return mUserValue != 0;
226 | }
227 |
228 | public synchronized void setUserValue(int digit) {
229 | this.mPossibles.clear();
230 | this.mUserValue = digit;
231 | mInvalidHighlight = false;
232 | }
233 |
234 | public synchronized void clearUserValue() {
235 | setUserValue(0);
236 | }
237 |
238 | public boolean isUserValueCorrect() {
239 | return mUserValue == mValue;
240 | }
241 |
242 | /* Returns whether the cell is a member of any cage */
243 | public boolean CellInAnyCage()
244 | {
245 | return mCageId != -1;
246 | }
247 |
248 | public void setSelectedCellColor(int color) {
249 | this.mSelectedPaint.setColor(color);
250 | }
251 |
252 | public void setLastModified(boolean value) {
253 | this.mLastModified = value;
254 | }
255 |
256 | public void setInvalidHighlight(boolean value) {
257 | this.mInvalidHighlight = value;
258 | }
259 | public boolean getInvalidHighlight() {
260 | return this.mInvalidHighlight;
261 | }
262 |
263 | public void setCheatedHighlight(boolean value) {
264 | this.mCheated = value;
265 | }
266 | public boolean getCheatedHighlight() {
267 | return this.mCheated;
268 | }
269 |
270 | /* Draw the cell. Border and text is drawn. */
271 | public void onDraw(Canvas canvas, boolean onlyBorders) {
272 |
273 | // Calculate x and y for the cell origin (topleft)
274 | float cellSize = (float)this.mContext.getMeasuredWidth() / (float)this.mContext.mGridSize;
275 | this.mPosX = cellSize * this.mColumn;
276 | this.mPosY = cellSize * this.mRow;
277 |
278 | float north = this.mPosY;
279 | float south = this.mPosY + cellSize;
280 | float east = this.mPosX + cellSize;
281 | float west = this.mPosX;
282 | GridCell cellAbove = this.mContext.getCellAt(this.mRow-1, this.mColumn);
283 | GridCell cellLeft = this.mContext.getCellAt(this.mRow, this.mColumn-1);
284 | GridCell cellRight = this.mContext.getCellAt(this.mRow, this.mColumn+1);
285 | GridCell cellBelow = this.mContext.getCellAt(this.mRow+1, this.mColumn);
286 |
287 | if (!onlyBorders) {
288 | if (this.isUserValueSet())
289 | canvas.drawRect(west+1, north+1, east-1, south-1, this.mUserSetPaint);
290 | if (this.mLastModified)
291 | canvas.drawRect(west+1, north+1, east-1, south-1, this.mLastModifiedPaint);
292 | if (this.mCheated)
293 | canvas.drawRect(west+1, north+1, east-1, south-1, this.mCheatedPaint);
294 | if ((this.mShowWarning && this.mContext.mDupedigits) || this.mInvalidHighlight)
295 | canvas.drawRect(west+1, north+1, east-1, south-1, this.mWarningPaint);
296 | if (this.mSelected)
297 | canvas.drawRect(west+1, north+1, east-1, south-1, this.mSelectedPaint);
298 | } else {
299 | if (this.mBorderTypes[NORTH] > 2)
300 | if (cellAbove == null)
301 | north += 2;
302 | else
303 | north += 1;
304 | if (this.mBorderTypes[WEST] > 2)
305 | if (cellLeft == null)
306 | west += 2;
307 | else
308 | west += 1;
309 | if (this.mBorderTypes[EAST] > 2)
310 | if (cellRight == null)
311 | east -= 3;
312 | else
313 | east -= 2;
314 | if (this.mBorderTypes[SOUTH] > 2)
315 | if (cellBelow == null)
316 | south -= 3;
317 | else
318 | south -= 2;
319 | }
320 | // North
321 | Paint borderPaint = this.getBorderPaint(NORTH);
322 | if (!onlyBorders && this.mBorderTypes[NORTH] > 2)
323 | borderPaint = this.mBorderPaint;
324 | if (borderPaint != null) {
325 | canvas.drawLine(west, north, east, north, borderPaint);
326 | }
327 |
328 | // East
329 | borderPaint = this.getBorderPaint(EAST);
330 | if (!onlyBorders && this.mBorderTypes[EAST] > 2)
331 | borderPaint = this.mBorderPaint;
332 | if (borderPaint != null)
333 | canvas.drawLine(east, north, east, south, borderPaint);
334 |
335 | // South
336 | borderPaint = this.getBorderPaint(SOUTH);
337 | if (!onlyBorders && this.mBorderTypes[SOUTH] > 2)
338 | borderPaint = this.mBorderPaint;
339 | if (borderPaint != null)
340 | canvas.drawLine(west, south, east, south, borderPaint);
341 |
342 | // West
343 | borderPaint = this.getBorderPaint(WEST);
344 | if (!onlyBorders && this.mBorderTypes[WEST] > 2)
345 | borderPaint = this.mBorderPaint;
346 | if (borderPaint != null) {
347 | canvas.drawLine(west, north, west, south, borderPaint);
348 | }
349 |
350 | if (onlyBorders)
351 | return;
352 |
353 | // Cell value
354 | if (this.isUserValueSet()) {
355 | int textSize = (int)(cellSize*3/4);
356 | this.mValuePaint.setTextSize(textSize);
357 | float leftOffset = cellSize/2 - textSize/4;
358 | float topOffset = cellSize/2 + textSize*2/5;
359 |
360 | canvas.drawText("" + this.mUserValue, this.mPosX + leftOffset,
361 | this.mPosY + topOffset, this.mValuePaint);
362 | }
363 |
364 | int cageTextSize = (int)(cellSize/3);
365 | this.mCageTextPaint.setTextSize(cageTextSize);
366 | // Cage text
367 | if (!this.mCageText.equals("")) {
368 | canvas.drawText(this.mCageText, this.mPosX + 2, this.mPosY + cageTextSize, this.mCageTextPaint);
369 |
370 | // canvas.drawText(this.mCageText, this.mPosX + 2, this.mPosY + 13, this.mCageTextPaint);
371 | }
372 |
373 | if (mPossibles.size()>0) {
374 | Activity activity = mContext.mContext;
375 | SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
376 | if (prefs.getBoolean("pencil3x3", true)) {
377 | this.mPossiblesPaint.setFakeBoldText(true);
378 | this.mPossiblesPaint.setTextSize((int)(cellSize/4.5));
379 | int xOffset = (int) (cellSize/3);
380 | int yOffset = (int) (cellSize/2) + 1;
381 | float xScale = (float) 0.21 * cellSize;
382 | float yScale = (float) 0.21 * cellSize;
383 | for (int i = 0 ; i < mPossibles.size() ; i++) {
384 | int possible = mPossibles.get(i);
385 | float xPos = mPosX + xOffset + ((possible-1)%3)*xScale;
386 | float yPos = mPosY + yOffset + ((possible-1) /3)*yScale;
387 | canvas.drawText(Integer.toString(possible), xPos, yPos, this.mPossiblesPaint);
388 | }
389 | }
390 | else {
391 | this.mPossiblesPaint.setFakeBoldText(false);
392 | mPossiblesPaint.setTextSize((int)(cellSize/4));
393 | String possibles = "";
394 | for (int i = 0 ; i < mPossibles.size() ; i++)
395 | possibles += Integer.toString(mPossibles.get(i));
396 | canvas.drawText(possibles, mPosX+3, mPosY + cellSize-5, mPossiblesPaint);
397 | }
398 | }
399 | }
400 |
401 | }
402 |
--------------------------------------------------------------------------------
/app/src/main/java/com/holokenmod/GridCage.java:
--------------------------------------------------------------------------------
1 | package com.holokenmod;
2 |
3 | import android.util.Log;
4 |
5 | import java.util.ArrayList;
6 | import java.util.Arrays;
7 |
8 | public class GridCage {
9 |
10 | public static final int OPERATIONS_ALL = 0;
11 | public static final int OPERATIONS_ADD_SUB = 1;
12 | public static final int OPERATIONS_ADD_MULT = 2;
13 | public static final int OPERATIONS_MULT = 3;
14 |
15 | public static final int ACTION_NONE = 0;
16 | public static final int ACTION_ADD = 1;
17 | public static final int ACTION_SUBTRACT = 2;
18 | public static final int ACTION_MULTIPLY = 3;
19 | public static final int ACTION_DIVIDE = 4;
20 |
21 | public static final int CAGE_UNDEF = -1;
22 | public static final int CAGE_1 = 0;
23 |
24 | // O = Origin (0,0) - must be the upper leftmost cell
25 | // X = Other cells used in cage
26 | public static final int [][][] CAGE_COORDS = new int[][][] {
27 | // O
28 | {{0,0}},
29 | // O
30 | // X
31 | {{0,0},{0,1}},
32 | // OX
33 | {{0,0},{1,0}},
34 | // O
35 | // X
36 | // X
37 | {{0,0},{0,1},{0,2}},
38 | // OXX
39 | {{0,0},{1,0},{2,0}},
40 | // O
41 | // XX
42 | {{0,0},{0,1},{1,1}},
43 | // O
44 | //XX
45 | {{0,0},{0,1},{-1,1}},
46 | // OX
47 | // X
48 | {{0,0},{1,0},{1,1}},
49 | // OX
50 | // X
51 | {{0,0},{1,0},{0,1}},
52 | // OX
53 | // XX
54 | {{0,0},{1,0},{0,1},{1,1}},
55 | // OX
56 | // X
57 | // X
58 | {{0,0},{1,0},{0,1},{0,2}},
59 | // OX
60 | // X
61 | // X
62 | //{{0,0},{1,0},{1,1},{1,2}},
63 | // O
64 | // X
65 | // XX
66 | //{{0,0},{0,1},{0,2},{1,2}},
67 | // O
68 | // X
69 | //XX
70 | {{0,0},{0,1},{0,2},{-1,2}},
71 | // OXX
72 | // X
73 | {{0,0},{1,0},{2,0},{0,1}},
74 | // OXX
75 | // X
76 | {{0,0},{1,0},{2,0},{2,1}},
77 | // O
78 | // XXX
79 | /*{{0,0},{0,1},{1,1},{2,1}},
80 | // O
81 | //XXX
82 | {{0,0},{-2,1},{-1,1},{0,1}},
83 | // O
84 | // XX
85 | // X
86 | {{0,0},{0,1},{0,2},{1,1}},
87 | // O
88 | //XX
89 | // X
90 | {{0,0},{0,1},{0,2},{-1,1}},
91 | // OXX
92 | // X
93 | {{0,0},{1,0},{2,0},{1,1}},
94 | // O
95 | //XXX
96 | {{0,0},{-1,1},{0,1},{1,1}},
97 | // OXXX
98 | {{0,0},{1,0},{2,0},{3,0}},
99 | // O
100 | // X
101 | // X
102 | // X
103 | {{0,0},{0,1},{0,2},{0,3}},
104 | // O
105 | // XX
106 | // X
107 | {{0,0},{0,1},{1,1},{1,2}},
108 | // O
109 | //XX
110 | //X
111 | {{0,0},{0,1},{-1,1},{-1,2}},
112 | // OX
113 | // XX
114 | {{0,0},{1,0},{1,1},{2,1}},
115 | // OX
116 | //XX
117 | {{0,0},{1,0},{0,1},{-1,1}}*/
118 | };
119 |
120 | // Action for the cage
121 | public int mAction;
122 | public String mActionStr;
123 | // Number the action results in
124 | public int mResult;
125 | // List of cage's cells
126 | public ArrayList mCells;
127 | // Type of the cage
128 | public int mType;
129 | // Id of the cage
130 | public int mId;
131 | // Enclosing context
132 | public GridView mContext;
133 | // User math is correct
134 | public boolean mUserMathCorrect;
135 | // Cage (or a cell within) is selected
136 | public boolean mSelected;
137 |
138 | // Cached list of numbers which satisfy the cage's arithmetic
139 | private ArrayList mPossibles;
140 |
141 | public GridCage (GridView context, int type) {
142 | this.mContext = context;
143 | mType = type;
144 | mPossibles = null;
145 | mUserMathCorrect = true;
146 | mSelected = false;
147 | mCells = new ArrayList();
148 | }
149 |
150 | public String toString() {
151 | String retStr = "";
152 | retStr += "Cage id: " + this.mId + ", Type: " + this.mType;
153 | retStr += ", Action: ";
154 | switch (this.mAction)
155 | {
156 | case ACTION_NONE:
157 | retStr += "None"; break;
158 | case ACTION_ADD:
159 | retStr += "Add"; break;
160 | case ACTION_SUBTRACT:
161 | retStr += "Subtract"; break;
162 | case ACTION_MULTIPLY:
163 | retStr += "Multiply"; break;
164 | case ACTION_DIVIDE:
165 | retStr += "Divide"; break;
166 | }
167 | retStr += ", ActionStr: " + this.mActionStr + ", Result: " + this.mResult;
168 | retStr += ", cells: ";
169 | for (GridCell cell : this.mCells)
170 | retStr += cell.mCellNumber + ", ";
171 | return retStr;
172 | }
173 |
174 | /*
175 | * Generates the arithmetic for the cage, semi-randomly.
176 | *
177 | * - If a cage has 3 or more cells, it can only be an add or multiply.
178 | * - else if the cells are evenly divisible, division is used, else
179 | * subtraction.
180 | */
181 | public void setArithmetic(int operationSet) {
182 | this.mAction = -1;
183 | if (this.mType == CAGE_1) {
184 | this.mAction = ACTION_NONE;
185 | this.mActionStr = "";
186 | this.mResult = this.mCells.get(0).mValue;
187 | return;
188 | }
189 | double rand = this.mContext.mRandom.nextDouble();
190 | double addChance = 0.25;
191 | double multChance = 0.5;
192 |
193 | if (operationSet == OPERATIONS_ADD_SUB) {
194 | if (this.mCells.size() > 2)
195 | addChance = 1.0;
196 | else
197 | addChance = 0.4;
198 | multChance = 0.0;
199 | }
200 | else if (operationSet == OPERATIONS_MULT) {
201 | addChance = 0.0;
202 | multChance = 1.0;
203 | }
204 | else if (this.mCells.size() > 2 || operationSet == OPERATIONS_ADD_MULT) { // force + and x only
205 | addChance = 0.5;
206 | multChance = 1.0;
207 | }
208 |
209 | if (rand <= addChance)
210 | this.mAction = ACTION_ADD;
211 | else if (rand <= multChance)
212 | this.mAction = ACTION_MULTIPLY;
213 |
214 | if (this.mAction == ACTION_ADD) {
215 | int total = 0;
216 | for (GridCell cell : this.mCells) {
217 | total += cell.mValue;
218 | }
219 | this.mResult = total;
220 | this.mActionStr = "+";
221 | }
222 | if (this.mAction == ACTION_MULTIPLY) {
223 | int total = 1;
224 | for (GridCell cell : this.mCells) {
225 | total *= cell.mValue;
226 | }
227 | this.mResult = total;
228 | this.mActionStr = "x";
229 | }
230 | if (this.mAction > -1) {
231 | return;
232 | }
233 |
234 | if (this.mCells.size() < 2) {
235 | Log.d("KenKen", "Why only length 1? Type: " + this);
236 | }
237 | int cell1Value = this.mCells.get(0).mValue;
238 | int cell2Value = this.mCells.get(1).mValue;
239 | int higher = cell1Value;
240 | int lower = cell2Value;
241 | boolean canDivide = false;
242 | if (cell1Value < cell2Value) {
243 | higher = cell2Value;
244 | lower = cell1Value;
245 | }
246 | if (higher % lower == 0 && operationSet != OPERATIONS_ADD_SUB)
247 | canDivide = true;
248 | if (canDivide) {
249 | this.mResult = higher / lower;
250 | this.mAction = ACTION_DIVIDE;
251 | // this.mCells.get(0).mCageText = this.mResult + "\367";
252 | this.mActionStr = "/";
253 | } else {
254 | this.mResult = higher - lower;
255 | this.mAction = ACTION_SUBTRACT;
256 | this.mActionStr = "-";
257 | }
258 | }
259 |
260 | /*
261 | * Sets the cageId of the cage's cells.
262 | */
263 | public void setCageId(int id) {
264 | this.mId = id;
265 | for (GridCell cell : this.mCells)
266 | cell.mCageId = this.mId;
267 | }
268 |
269 |
270 | public boolean isAddMathsCorrect()
271 | {
272 | int total = 0;
273 | for (GridCell cell : this.mCells) {
274 | total += cell.getUserValue();
275 | }
276 | return (total == this.mResult);
277 | }
278 |
279 | public boolean isMultiplyMathsCorrect()
280 | {
281 | int total = 1;
282 | for (GridCell cell : this.mCells) {
283 | total *= cell.getUserValue();
284 | }
285 | return (total == this.mResult);
286 | }
287 |
288 | public boolean isDivideMathsCorrect()
289 | {
290 | if (this.mCells.size() != 2)
291 | return false;
292 |
293 | if (this.mCells.get(0).getUserValue() > this.mCells.get(1).getUserValue())
294 | return this.mCells.get(0).getUserValue() == (this.mCells.get(1).getUserValue() * this.mResult);
295 | else
296 | return this.mCells.get(1).getUserValue() == (this.mCells.get(0).getUserValue() * this.mResult);
297 | }
298 |
299 | public boolean isSubtractMathsCorrect()
300 | {
301 | if (this.mCells.size() != 2)
302 | return false;
303 |
304 | if (this.mCells.get(0).getUserValue() > this.mCells.get(1).getUserValue())
305 | return (this.mCells.get(0).getUserValue() - this.mCells.get(1).getUserValue()) == this.mResult;
306 | else
307 | return (this.mCells.get(1).getUserValue() - this.mCells.get(0).getUserValue()) == this.mResult;
308 | }
309 |
310 | // Returns whether the user values in the cage match the cage text
311 | public boolean isMathsCorrect() {
312 | if (this.mCells.size() == 1)
313 | return this.mCells.get(0).isUserValueCorrect();
314 |
315 | if (this.mContext.mShowOperators) {
316 | switch (this.mAction) {
317 | case ACTION_ADD :
318 | return isAddMathsCorrect();
319 | case ACTION_MULTIPLY :
320 | return isMultiplyMathsCorrect();
321 | case ACTION_DIVIDE :
322 | return isDivideMathsCorrect();
323 | case ACTION_SUBTRACT :
324 | return isSubtractMathsCorrect();
325 | }
326 | }
327 | else {
328 | return isAddMathsCorrect() || isMultiplyMathsCorrect() ||
329 | isDivideMathsCorrect() || isSubtractMathsCorrect();
330 |
331 | }
332 | throw new RuntimeException("isSolved() got to an unreachable point " +
333 | this.mAction + ": " + this.toString());
334 | }
335 |
336 | // Determine whether user entered values match the arithmetic.
337 | //
338 | // Only marks cells bad if all cells have a uservalue, and they dont
339 | // match the arithmetic hint.
340 | public void userValuesCorrect() {
341 | this.mUserMathCorrect = true;
342 | for (GridCell cell : this.mCells)
343 | if (!cell.isUserValueSet()) {
344 | this.setBorders();
345 | return;
346 | }
347 | this.mUserMathCorrect = this.isMathsCorrect();
348 | this.setBorders();
349 | }
350 |
351 | /*
352 | * Sets the borders of the cage's cells.
353 | */
354 | public void setBorders() {
355 | for (GridCell cell : this.mCells) {
356 | for(int x = 0 ; x < 4 ; x++) {
357 | cell.mBorderTypes[x] = 0;
358 | }
359 | if (this.mContext.CageIdAt(cell.mRow-1, cell.mColumn) != this.mId)
360 | if (!this.mUserMathCorrect && this.mContext.mBadMaths)
361 | cell.mBorderTypes[0] = GridCell.BORDER_WARN;
362 | else if (this.mSelected)
363 | cell.mBorderTypes[0] = GridCell.BORDER_CAGE_SELECTED;
364 | else
365 | cell.mBorderTypes[0] = GridCell.BORDER_SOLID;
366 |
367 | if (this.mContext.CageIdAt(cell.mRow, cell.mColumn+1) != this.mId)
368 | if(!this.mUserMathCorrect && this.mContext.mBadMaths)
369 | cell.mBorderTypes[1] = GridCell.BORDER_WARN;
370 | else if (this.mSelected)
371 | cell.mBorderTypes[1] = GridCell.BORDER_CAGE_SELECTED;
372 | else
373 | cell.mBorderTypes[1] = GridCell.BORDER_SOLID;
374 |
375 | if (this.mContext.CageIdAt(cell.mRow+1, cell.mColumn) != this.mId)
376 | if(!this.mUserMathCorrect && this.mContext.mBadMaths)
377 | cell.mBorderTypes[2] = GridCell.BORDER_WARN;
378 | else if (this.mSelected)
379 | cell.mBorderTypes[2] = GridCell.BORDER_CAGE_SELECTED;
380 | else
381 | cell.mBorderTypes[2] = GridCell.BORDER_SOLID;
382 |
383 | if (this.mContext.CageIdAt(cell.mRow, cell.mColumn-1) != this.mId)
384 | if(!this.mUserMathCorrect && this.mContext.mBadMaths)
385 | cell.mBorderTypes[3] = GridCell.BORDER_WARN;
386 | else if (this.mSelected)
387 | cell.mBorderTypes[3] = GridCell.BORDER_CAGE_SELECTED;
388 | else
389 | cell.mBorderTypes[3] = GridCell.BORDER_SOLID;
390 | }
391 | }
392 |
393 |
394 |
395 |
396 |
397 | /****
398 | * AC: For hinting system?
399 | *
400 | */
401 | public ArrayList getPossibleNums()
402 | {
403 | if (mPossibles == null) {
404 | if (this.mContext.mShowOperators)
405 | mPossibles = setPossibleNums();
406 | else
407 | mPossibles = setPossibleNumsNoOperator();
408 | }
409 | return mPossibles;
410 | }
411 |
412 | private ArrayList setPossibleNumsNoOperator()
413 | {
414 | ArrayList AllResults = new ArrayList();
415 |
416 | if (this.mAction == ACTION_NONE) {
417 | assert (mCells.size() == 1);
418 | int number[] = {mResult};
419 | AllResults.add(number);
420 | return AllResults;
421 | }
422 |
423 | if (mCells.size() == 2) {
424 | for (int i1=1; i1<=this.mContext.mGridSize; i1++)
425 | for (int i2=i1+1; i2<=this.mContext.mGridSize; i2++)
426 | if (i2 - i1 == mResult || i1 - i2 == mResult || mResult*i1 == i2 ||
427 | mResult*i2 == i1 || i1+i2 == mResult || i1*i2 == mResult) {
428 | int numbers[] = {i1, i2};
429 | AllResults.add(numbers);
430 | numbers = new int[] {i2, i1};
431 | AllResults.add(numbers);
432 | }
433 | return AllResults;
434 | }
435 |
436 | // ACTION_ADD:
437 | AllResults = getalladdcombos(this.mContext.mGridSize,mResult,mCells.size());
438 |
439 | // ACTION_MULTIPLY:
440 | ArrayList multResults = getallmultcombos(this.mContext.mGridSize,mResult,mCells.size());
441 |
442 | // Combine Add & Multiply result sets
443 | for (int[] possibleset: multResults)
444 | {
445 | boolean foundset = false;
446 | for (int[] currentset: AllResults) {
447 | if (Arrays.equals(possibleset, currentset)) {
448 | foundset = true;
449 | break;
450 | }
451 | }
452 | if (!foundset)
453 | AllResults.add(possibleset);
454 | }
455 |
456 | return AllResults;
457 | }
458 |
459 | /*
460 | * Generates all combinations of numbers which satisfy the cage's arithmetic
461 | * and MathDoku constraints i.e. a digit can only appear once in a column/row
462 | */
463 | private ArrayList setPossibleNums()
464 | {
465 | ArrayList AllResults = new ArrayList();
466 |
467 | switch (this.mAction) {
468 | case ACTION_NONE:
469 | assert (mCells.size() == 1);
470 | int number[] = {mResult};
471 | AllResults.add(number);
472 | break;
473 | case ACTION_SUBTRACT:
474 | assert(mCells.size() == 2);
475 | for (int i1=1; i1<=this.mContext.mGridSize; i1++)
476 | for (int i2=i1+1; i2<=this.mContext.mGridSize; i2++)
477 | if (i2 - i1 == mResult || i1 - i2 == mResult) {
478 | int numbers[] = {i1, i2};
479 | AllResults.add(numbers);
480 | numbers = new int[] {i2, i1};
481 | AllResults.add(numbers);
482 | }
483 | break;
484 | case ACTION_DIVIDE:
485 | assert(mCells.size() == 2);
486 | for (int i1=1; i1<=this.mContext.mGridSize; i1++)
487 | for (int i2=i1+1; i2<=this.mContext.mGridSize; i2++)
488 | if (mResult*i1 == i2 || mResult*i2 == i1) {
489 | int numbers[] = {i1, i2};
490 | AllResults.add(numbers);
491 | numbers = new int[] {i2, i1};
492 | AllResults.add(numbers);
493 | }
494 | break;
495 | case ACTION_ADD:
496 | AllResults = getalladdcombos(this.mContext.mGridSize,mResult,mCells.size());
497 | break;
498 | case ACTION_MULTIPLY:
499 | AllResults = getallmultcombos(this.mContext.mGridSize,mResult,mCells.size());
500 | break;
501 | }
502 | return AllResults;
503 | }
504 |
505 | // The following two variables are required by the recursive methods below.
506 | // They could be passed as parameters of the recursive methods, but this
507 | // reduces performance.
508 | private int[] numbers;
509 | private ArrayList result_set;
510 |
511 | private ArrayList getalladdcombos (int max_val, int target_sum, int n_cells)
512 | {
513 | numbers = new int[n_cells];
514 | result_set = new ArrayList ();
515 | getaddcombos(max_val, target_sum, n_cells);
516 | return result_set;
517 | }
518 |
519 | /*
520 | * Recursive method to calculate all combinations of digits which add up to target
521 | *
522 | * @param max_val maximum permitted value of digit (= dimension of grid)
523 | * @param target_sum the value which all the digits should add up to
524 | * @param n_cells number of digits still to select
525 | */
526 | private void getaddcombos(int max_val, int target_sum, int n_cells)
527 | {
528 | for (int n=1; n<= max_val; n++)
529 | {
530 | if (n_cells == 1)
531 | {
532 | if (n == target_sum) {
533 | numbers[0] = n;
534 | if (satisfiesConstraints(numbers))
535 | result_set.add(numbers.clone());
536 | }
537 | }
538 | else {
539 | numbers[n_cells-1] = n;
540 | getaddcombos(max_val, target_sum-n, n_cells-1);
541 | }
542 | }
543 | return;
544 | }
545 |
546 | private ArrayList getallmultcombos (int max_val, int target_sum, int n_cells)
547 | {
548 | numbers = new int[n_cells];
549 | result_set = new ArrayList ();
550 | getmultcombos(max_val, target_sum, n_cells);
551 |
552 | return result_set;
553 | }
554 |
555 | /*
556 | * Recursive method to calculate all combinations of digits which multiply up to target
557 | *
558 | * @param max_val maximum permitted value of digit (= dimension of grid)
559 | * @param target_sum the value which all the digits should multiply up to
560 | * @param n_cells number of digits still to select
561 | */
562 | private void getmultcombos(int max_val, int target_sum, int n_cells)
563 | {
564 | for (int n=1; n<= max_val; n++)
565 | {
566 | if (target_sum % n != 0)
567 | continue;
568 |
569 | if (n_cells == 1)
570 | {
571 | if (n == target_sum) {
572 | numbers[0] = n;
573 | if (satisfiesConstraints(numbers))
574 | result_set.add(numbers.clone());
575 | }
576 | }
577 | else {
578 | numbers[n_cells-1] = n;
579 | getmultcombos(max_val, target_sum/n, n_cells-1);
580 | }
581 | }
582 | return;
583 | }
584 |
585 | /*
586 | * Check whether the set of numbers satisfies all constraints
587 | * Looking for cases where a digit appears more than once in a column/row
588 | * Constraints:
589 | * 0 -> (mGridSize * mGridSize)-1 = column constraints
590 | * (each column must contain each digit)
591 | * mGridSize * mGridSize -> 2*(mGridSize * mGridSize)-1 = row constraints
592 | * (each row must contain each digit)
593 | */
594 | private boolean satisfiesConstraints(int[] test_nums) {
595 |
596 | boolean constraints[] = new boolean[mContext.mGridSize*mContext.mGridSize*2];
597 | int constraint_num;
598 | for (int i = 0; i