Celtic Knot game

A valid Celtic knot appears, but it's messed up. You tidy it up by rotating the tiles.

Stringsapp/res/values/strings.xml
Screen formatapp/res/layout/activity_main.xml
Code for appapp/java/com.(the project name)/MainActivity
Code for tile gridviewapp/java/com.(the project name)/ImageTile



app/manifests/AndroidManifest.xml - to force orientation

<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.edkins.mosaic" > <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" android:screenOrientation="portrait"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>


app/res/drawable - pictures

There are 6 x 16 image files (17 per style). The styles are "close", "loose", "stone", "simple", "roman" and "border" and the files are, e.g., "close0" (background) to "close16". They give the various parts of the knot. They are loaded into an arrays defined in in app/java/com.(the project name)/MainActivity and used in app/java/com.(the project name)/ImagePalette and app/java/com.(the project name)/ImageTile. The number of styles (6) is defined in app/java/com.(the project name)/MainActivity.




app/res/mipmap/ic_launcher.png/ - icon for launching app




app/res/values/strings.xml - strings

<resources> <string name="app_name">CelticKnotGame</string> <string name="howTo">Make knot by tapping on tile to rotate</string> <string name="clearMessage">new</string> <string name="styleMessage">change style</string> <string name="sizeSmall">small</string> <string name="sizeMedium">medium</string> <string name="sizeLarge">large</string> <string name="space">" "</string> <string name="finished">"Knot is complete! Click on New."</string> </resources>


app/res/layout/activity_main.xml - screen format

<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity"> <TextView android:id="@+id/message" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/howTo" android:layout_centerHorizontal="true" /> <GridView android:id="@+id/tileView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingTop="@dimen/activity_vertical_margin" android:numColumns="10" android:layout_below="@id/message" /> <TextView android:id="@+id/finishMessage" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/space" android:paddingTop="@dimen/activity_vertical_margin" android:layout_centerHorizontal="true" android:layout_below="@id/tileView" /> <RadioGroup xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/size" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" android:layout_below="@id/finishMessage" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:layout_centerHorizontal="true" > <RadioButton android:id="@+id/sizeSmall" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/sizeSmall" android:onClick="clickSmall" /> <RadioButton android:id="@+id/sizeMedium" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/sizeMedium" android:onClick="clickMedium" /> <RadioButton android:id="@+id/sizeLarge" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/sizeLarge" android:onClick="clickLarge" /> </RadioGroup> <Button android:id="@+id/clearButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/clearMessage" android:onClick="doNew" android:layout_below="@id/finishMessage" android:layout_toLeftOf="@id/size" android:layout_toStartOf="@id/size" /> <Button android:id="@+id/styleButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/styleMessage" android:onClick="doStyle" android:layout_below="@id/finishMessage" android:layout_toRightOf="@id/size" android:layout_toEndOf="@id/size" /> </RelativeLayout>


app/java/com.(the project name)/MainActivity - main code for app

package com.edkins.celticknotgame; import ... public class MainActivity extends AppCompatActivity { // style of knot and number of styles public static int styleType = 1; public static int styleNum = 6; public static Random randomNum = new Random(); public static int width = 4; public static int complete = 0; // tiles - for setting up tessera public static int [] tile = new int [100]; public static int [] ok = new int [100]; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); newKnot(); GridView matrix = (GridView) findViewById(R.id.tileView); matrix.setAdapter(new ImageTile(this)); matrix.setOnItemClickListener(new AdapterView.OnItemClickListener() { public void onItemClick(AdapterView<?> parent, View v, int position, long id) { processTileClick(position); } }); RadioButton size = (RadioButton) findViewById(R.id.sizeSmall); size.setChecked(true); width = 4; } // Main process - tap to rotate pattern plus check if knot completed public void processTileClick(int position) { if (complete==1) {return;} if (tile[position] < 2 || tile[position]== 16) {return;} if (tile [position] == 5) {tile[position] = 2;} else if (tile [position] == 9) {tile[position] = 6;} else if (tile [position] == 11) {tile[position] = 10;} else if (tile [position] == 15) {tile[position] = 12;} else {tile[position] ++;} redo(); complete = 1; for (int i=0; i<100; i++) { if (ok [i] != tile[i]) {complete = i;} } if (complete == 1) {hooray();} } // next game public void newKnot() { complete = 0; TextView finish = (TextView) findViewById(R.id.finishMessage); finish.setText(R.string.space); setTilesToOne(); makeKnot(); shuffle(); } //set tiles within knot area to one (non-zero) - leave 20% zero public void setTilesToOne() { for (int i=0; i<100; i++) {tile[i] = 0;} int st = 5 - width / 2; int fin = st + width - 1; for (int x=st; x<=fin; x++) { for (int y=st; y<=fin; y++) { if (randomNum.nextInt(5)>0) {tile[y * 10 + x] = 1;} } } } // make the tiles into a proper knot public void makeKnot() { for (int x=0; x<10; x++) { for (int y=0; y<10; y++) { int position = y*10 + x; int n = checkNext(x, y-1); int s = checkNext(x, y+1); int w = checkNext(x-1, y); int e = checkNext(x+1, y); if (tile[position]>0) { if (n == 0 && e == 0 && s == 0 && w == 0) {tile[position] = 1;} else if (n == 0 && e == 0 && s == 1 && w == 0) {tile[position] = 2;} else if (n == 0 && e == 0 && s == 0 && w == 1) {tile[position] = 3;} else if (n == 1 && e == 0 && s == 0 && w == 0) {tile[position] = 4;} else if (n == 0 && e == 1 && s == 0 && w == 0) {tile[position] = 5;} else if (n == 0 && e == 1 && s == 1 && w == 0) {tile[position] = 6;} else if (n == 0 && e == 0 && s == 1 && w == 1) {tile[position] = 7;} else if (n == 1 && e == 0 && s == 0 && w == 1) {tile[position] = 8;} else if (n == 1 && e == 1 && s == 0 && w == 0) {tile[position] = 9;} else if (n == 0 && e == 1 && s == 0 && w == 1) {tile[position] = 10;} else if (n == 1 && e == 0 && s == 1 && w == 0) {tile[position] = 11;} else if (n == 0 && e == 1 && s == 1 && w == 1) {tile[position] = 12;} else if (n == 1 && e == 0 && s == 1 && w == 1) {tile[position] = 13;} else if (n == 1 && e == 1 && s == 0 && w == 1) {tile[position] = 14;} else if (n == 1 && e == 1 && s == 1 && w == 0) {tile[position] = 15;} else {tile[position] = 16;} } } } // make copy for checking is OK for (int i=0; i<100; i++) { if (tile[i]<2) {tile[i] = 0;} ok [i] = tile[i]; } } // check next door tiles to see if they are part of the knot public int checkNext(int x, int y) { if (x<0 || x>9 || y<0 || y>9) {return 0;} int position = y*10 + x; if (tile [position]==0) {return 0;} else {return 1;} } // shuffle the tiles public void shuffle() { for (int x=0; x<10; x++) { for (int y=0; y<10; y++) { int position = y * 10 + x; if (tile[position]<2) {tile[position] = 0;} else if (tile[position] < 6) {tile[position] = 2 + randomNum.nextInt(4);} else if (tile[position] < 10) {tile[position] = 6 + randomNum.nextInt(4);} else if (tile[position] < 12) {tile[position] = 10 + randomNum.nextInt(2);} else if (tile[position] < 15) {tile[position] = 12 + randomNum.nextInt(4);} } } } // what happens when knot is complete public void hooray() { TextView finish = (TextView) findViewById(R.id.finishMessage); finish.setText(R.string.finished); int st = 3 - width / 2; int fin = st + width +3; if (width==8) {st = 0; fin = 9;} for (int x=(st+1); x<fin; x++) { tile[st * 10 + x] = 10; tile[fin * 10 + x] = 10; } for (int y=(st+1); y<fin; y++) { tile[y * 10 + st] = 11; tile[y * 10 + fin] = 11; } tile[st * 10 + st] = 6; tile[st * 10 + fin] = 7; tile[fin * 10 + st] = 9; tile[fin * 10 + fin] = 8; redo(); } // buttons, etc // next knot public void doNew(View view) { newKnot(); styleType = (styleType + randomNum.nextInt(4) + 1) % styleNum; redo(); } // change style public void doStyle(View view) { styleType = (styleType + 1) % styleNum; redo(); } // change size of knot public void clickSmall(View view) { width = 4; styleType = (styleType + randomNum.nextInt(4) + 1) % styleNum; newKnot(); redo(); } public void clickMedium(View view) { width = 6; styleType = (styleType + randomNum.nextInt(4) + 1) % styleNum; newKnot(); redo(); } public void clickLarge(View view) {width = 8; styleType = (styleType + randomNum.nextInt(4) + 1) % styleNum; newKnot(); redo(); } // redo screen public void redo() { GridView matrix = (GridView) findViewById(R.id.tileView); matrix.setAdapter(new ImageTile(this)); } // Style - close knot public static Integer[] close = { R.drawable.close0, R.drawable.close1, R.drawable.close2, R.drawable.close3, R.drawable.close4, R.drawable.close5, R.drawable.close6, R.drawable.close7, R.drawable.close8, R.drawable.close9, R.drawable.close10, R.drawable.close11, R.drawable.close12, R.drawable.close13, R.drawable.close14, R.drawable.close15, R.drawable.close16 }; // Style - loose knot public static Integer[] loose = { R.drawable.loose0, R.drawable.loose1, R.drawable.loose2, R.drawable.loose3, R.drawable.loose4, R.drawable.loose5, R.drawable.loose6, R.drawable.loose7, R.drawable.loose8, R.drawable.loose9, R.drawable.loose10, R.drawable.loose11, R.drawable.loose12, R.drawable.loose13, R.drawable.loose14, R.drawable.loose15, R.drawable.loose16 }; // Style - stone knot public static Integer[] stone = { R.drawable.stone0, R.drawable.stone1, R.drawable.stone2, R.drawable.stone3, R.drawable.stone4, R.drawable.stone5, R.drawable.stone6, R.drawable.stone7, R.drawable.stone8, R.drawable.stone9, R.drawable.stone10, R.drawable.stone11, R.drawable.stone12, R.drawable.stone13, R.drawable.stone14, R.drawable.stone15, R.drawable.stone16 }; // Style - simple knot public static Integer[] simple = { R.drawable.simple0, R.drawable.simple1, R.drawable.simple2, R.drawable.simple3, R.drawable.simple4, R.drawable.simple5, R.drawable.simple6, R.drawable.simple7, R.drawable.simple8, R.drawable.simple9, R.drawable.simple10, R.drawable.simple11, R.drawable.simple12, R.drawable.simple13, R.drawable.simple14, R.drawable.simple15, R.drawable.simple16 }; // Style - Roman mosaic public static Integer[] roman = { R.drawable.roman0, R.drawable.roman1, R.drawable.roman2, R.drawable.roman3, R.drawable.roman4, R.drawable.roman5, R.drawable.roman6, R.drawable.roman7, R.drawable.roman8, R.drawable.roman9, R.drawable.roman10, R.drawable.roman11, R.drawable.roman12, R.drawable.roman13, R.drawable.roman14, R.drawable.roman15, R.drawable.roman16 }; // Style - knot with border public static Integer[] border = { R.drawable.border0, R.drawable.border1, R.drawable.border2, R.drawable.border3, R.drawable.border4, R.drawable.border5, R.drawable.border6, R.drawable.border7, R.drawable.border8, R.drawable.border9, R.drawable.border10, R.drawable.border11, R.drawable.border12, R.drawable.border13, R.drawable.border14, R.drawable.border15, R.drawable.border16 }; }


app/java/com.(the project name)/ImageTile - code for tile gridview - a new file, see above

package com.edkins.celticknotgame; import ... public class ImageTile extends BaseAdapter { private AppCompatActivity mContext; public ImageTile(AppCompatActivity c) {mContext = c;} public int getCount() {return 100;} public Object getItem(int position) {return null;} public long getItemId(int position) {return 0;} // create new ImageView for tile public View getView(int position, View convertView, ViewGroup parent) { ImageView imageView; if (convertView == null) { imageView = new ImageView(mContext); GridView tile = (GridView) mContext.findViewById(R.id.tileView); int w = tile.getWidth() / 10; imageView.setLayoutParams(new GridView.LayoutParams(w, w)); } else { imageView = (ImageView) convertView; } // initialise the view element (to whatever is in array tile[]) int sub = MainActivity.tile[position]; if (MainActivity.styleType == 0) { imageView.setImageResource(MainActivity.close[sub]); } else if (MainActivity.styleType == 1) { imageView.setImageResource(MainActivity.loose[sub]); } else if (MainActivity.styleType == 2) { imageView.setImageResource(MainActivity.stone[sub]); } else if (MainActivity.styleType == 3) { imageView.setImageResource(MainActivity.simple[sub]); } else if (MainActivity.styleType == 4) { imageView.setImageResource(MainActivity.roman[sub]); } else if (MainActivity.styleType == 5) { imageView.setImageResource(MainActivity.border[sub]); } return imageView; } }


Index to my other websites

© Jo Edkins 2016