Make a more complex Celtic knot

In Add option, you choose a knot element and rotate it. In Turn option, you can rotate any element. You can alter the colours of the completed knots.

Stringsapp/res/values/strings.xml
Screen formatapp/res/layout/activity_main.xml
Code for appapp/java/com.(the project name)/MainActivity
Code for option type gridviewapp/java/com.(the project name)/ImageType
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 7 x 15 image files (15 per colour). The colours are "black", "blue", "green", "red", "white", "yellow" and "cyan" and the files are, e.g., "black0" (background) to "black14". 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. There are also colour squares (for changing colour).




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




app/res/values/strings.xml - strings

<resources> <string name="app_name">Construct a Celtic Knot</string> <string name="howTo0">Choose element, tap below to position, tap again to turn</string> <string name="howTo1">Tap on any element below to turn</string> <string name="howTo2">Choose colour, then tap on completed knot</string> <string name="clearMessage">new</string> <string name="option0">Add</string> <string name="option1">Turn</string> <string name="option2">Colour</string> <string name="option3">New knot</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"> <RadioGroup xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/options" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingBottom="@dimen/activity_vertical_margin" android:orientation="horizontal" android:layout_centerHorizontal="true" > <RadioButton android:id="@+id/option0" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/option0" android:onClick="clickOption0" /> <RadioButton android:id="@+id/option1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/option1" android:onClick="clickOption1" /> <RadioButton android:id="@+id/option2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/option2" android:onClick="clickOption2" /> <RadioButton android:id="@+id/option3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/option3" android:onClick="clickOption3" /> </RadioGroup> <GridView android:id="@+id/typeView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingLeft="100dp" android:paddingRight="100dp" android:numColumns="6" android:layout_below="@id/options" /> <TextView android:id="@+id/message" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:paddingTop="@dimen/activity_vertical_margin" android:text="@string/howTo0" android:layout_below="@id/typeView" /> <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" /> </RelativeLayout>


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

package com.edkins.celticknots2; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.AdapterView; import android.widget.GridView; import android.widget.RadioButton; import android.widget.Toast; public class MainActivity extends AppCompatActivity { public static int option = 0; public static int col = 1; public static int width = 10; public static int knotType = 1; public static int knotPos = 1; public static int knotNum = 0; // tiles - for setting up knot and colours public static int [] tile = new int [width * width]; public static int [] colour = new int [width * width]; public static int [] knot = new int [width * width]; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); RadioButton acc = (RadioButton) findViewById(R.id.option0); acc.setChecked(true); option = 0; newKnot(); GridView typeV = (GridView) findViewById(R.id.typeView); typeV.setAdapter(new ImageType(this)); typeV.setOnItemClickListener(new AdapterView.OnItemClickListener() { public void onItemClick(AdapterView<?> parent, View v, int position, long id) { processTypeClick(position); } }); GridView tileV = (GridView) findViewById(R.id.tileView); tileV.setAdapter(new ImageTile(this)); tileV.setOnItemClickListener(new AdapterView.OnItemClickListener() { public void onItemClick(AdapterView<?> parent, View v, int position, long id) { processTileClick(position); } }); } // Main process - tap to rotate pattern plus check if knot completed public void processTileClick(int position) { if (option==0) { if (knotType == 0 && tile[position] == 0) { Toast.makeText(getApplicationContext(), "Choose an element above first", Toast.LENGTH_SHORT).show(); } else if (knotSame(position)) {turnKnot(position);} else { tile[position] = knotType; colour[position] = 0; knot[position] = 0; } } else if (option==1) {turnKnot(position);} else if (option==2) { if (knot[position]==0) { Toast.makeText(getApplicationContext(), "You can only colour a complete knot", Toast.LENGTH_SHORT).show(); } else { int thisKnot=knot[position]; for (int j=0; j<(width * width); j++) { if (knot[j]==thisKnot) {colour[j]=col;} } } } checkTiles(); redo(); } // turn knot public void turnKnot(int position) { if (tile[position] == 0 || tile[position] == 15) { Toast.makeText(getApplicationContext(), "You can\'t turn this", Toast.LENGTH_SHORT).show(); } else if (tile[position] == 4) {tile[position] = 1;} else if (tile[position] == 8) {tile[position] = 5;} else if (tile[position] == 10) {tile[position] = 9;} else if (tile[position] == 14) {tile[position] = 11;} else {tile[position]++;} } // check if same knot public boolean knotSame(int position) { if (tile[position] >= 1 && tile[position] <= 4) { if (knotType >= 1 && knotType <= 4) {return true;} } else if (tile[position] >= 5 && tile[position] <= 8) { if (knotType >= 5 && knotType <= 8) {return true;} } else if (tile[position] >= 9 && tile[position] <= 10) { if (knotType >= 9 && knotType <= 10) {return true;} } else if (tile[position] >= 11 && tile[position] <= 14) { if (knotType >= 11 && knotType <= 14) {return true;} } else if (tile[position] == 15 && knotType == 15) {return true;} return false; } // check if knots OK public void checkTiles() { int ok=1; int i; int j; for (i=0; i<(width * width ); i++) { if (tile[i] > 0) { int type = tile[i]; int x = i % width; int y = i / width; if (nJoin[type] == 1) { j = i - width; if (y==0) {ok = 0; undoKnot(i);} else if (colour[j] != colour[i]) {ok = 0; undoKnot(i);} else if (sJoin[tile[j]] == 0) {ok = 0; undoKnot(i);} } if (eJoin[type] == 1) { j = i + 1; if (x>=(width-1)) {ok = 0; undoKnot(i);} else if (colour[j] != colour[i]) {ok = 0; undoKnot(i);} else if (wJoin[tile[j]] == 0) {ok = 0; undoKnot(i);} } if (sJoin[type] == 1) { j = i + width; if (y>=(width-1)) {ok = 0; undoKnot(i);} else if (colour[j] != colour[i]) {ok = 0; undoKnot(i);} else if (nJoin[tile[j]] == 0) {ok = 0; undoKnot(i);} } if (wJoin[type] == 1) { j = i - 1; if (x==0) {ok = 0; undoKnot(i);} else if (colour[j] != colour[i]) {ok = 0; undoKnot(i);} else if (eJoin[tile[j]] == 0) {ok = 0; undoKnot(i);} } } } knotNum++; if (ok==1) { for (i=0; i<(width * width ); i++) { if (tile[i] > 0 && colour[i] == 0) {colour[i] = col; knot[i]=knotNum;} } } } public void undoKnot(int i) { int wrongKnot=knot[i]; for (int j=0; j<(width * width ); j++) { if (knot[j]==wrongKnot) {colour[j]=0; knot[j]=0;} } } public void newKnot() { for (int i=0; i<(width * width); i++) { colour[i] = 0; tile[i] = 0; knot [i] = 0; } knotNum = 0; } // redo main grid public void redo() { GridView tileV = (GridView) findViewById(R.id.tileView); tileV.setAdapter(new ImageTile(this)); } public void processTypeClick(int position) { if (option==0) { knotPos = position; if (position == 0) {knotType = 0;} else if (position == 1) {knotType = 1;} else if (position == 2) {knotType = 5;} else if (position == 3) {knotType = 9;} else if (position == 4) {knotType = 11;} else if (position == 5) {knotType = 15;} } else if (option==1) { Toast.makeText(getApplicationContext(), "Tap below, not here", Toast.LENGTH_SHORT).show(); } else if (option==2) {col = position+1;} redoType(); } // options public void clickOption0(View view) {option=0; redoType();} public void clickOption1(View view) {option=1; redoType();} public void clickOption2(View view) {option=2; redoType();} public void clickOption3(View view) { newKnot(); redo(); option=0; RadioButton acc = (RadioButton) findViewById(R.id.option0); acc.setChecked(true); option = 0; redoType(); } // redo options public void redoType() { GridView typeV = (GridView) findViewById(R.id.typeView); typeV.setAdapter(new ImageType(this)); } // Different colours of knot public static int [] black = { R.drawable.black0, R.drawable.black1, R.drawable.black2, R.drawable.black3, R.drawable.black4, R.drawable.black5, R.drawable.black6, R.drawable.black7, R.drawable.black8, R.drawable.black9, R.drawable.black10, R.drawable.black11, R.drawable.black12, R.drawable.black13, R.drawable.black14, R.drawable.black15 }; public static int [] red = { R.drawable.black0, R.drawable.red1, R.drawable.red2, R.drawable.red3, R.drawable.red4, R.drawable.red5, R.drawable.red6, R.drawable.red7, R.drawable.red8, R.drawable.red9, R.drawable.red10, R.drawable.red11, R.drawable.red12, R.drawable.red13, R.drawable.red14, R.drawable.red15 }; public static int [] blue = { R.drawable.black0, R.drawable.blue1, R.drawable.blue2, R.drawable.blue3, R.drawable.blue4, R.drawable.blue5, R.drawable.blue6, R.drawable.blue7, R.drawable.blue8, R.drawable.blue9, R.drawable.blue10, R.drawable.blue11, R.drawable.blue12, R.drawable.blue13, R.drawable.blue14, R.drawable.blue15 }; public static int [] yellow = { R.drawable.black0, R.drawable.yellow1, R.drawable.yellow2, R.drawable.yellow3, R.drawable.yellow4, R.drawable.yellow5, R.drawable.yellow6, R.drawable.yellow7, R.drawable.yellow8, R.drawable.yellow9, R.drawable.yellow10, R.drawable.yellow11, R.drawable.yellow12, R.drawable.yellow13, R.drawable.yellow14, R.drawable.yellow15 }; public static int [] green = { R.drawable.black0, R.drawable.green1, R.drawable.green2, R.drawable.green3, R.drawable.green4, R.drawable.green5, R.drawable.green6, R.drawable.green7, R.drawable.green8, R.drawable.green9, R.drawable.green10, R.drawable.green11, R.drawable.green12, R.drawable.green13, R.drawable.green14, R.drawable.green15 }; public static int [] cyan = { R.drawable.black0, R.drawable.cyan1, R.drawable.cyan2, R.drawable.cyan3, R.drawable.cyan4, R.drawable.cyan5, R.drawable.cyan6, R.drawable.cyan7, R.drawable.cyan8, R.drawable.cyan9, R.drawable.cyan10, R.drawable.cyan11, R.drawable.cyan12, R.drawable.cyan13, R.drawable.cyan14, R.drawable.cyan15 }; public static int [] white = { R.drawable.black0, R.drawable.white1, R.drawable.white2, R.drawable.white3, R.drawable.white4, R.drawable.white5, R.drawable.white6, R.drawable.white7, R.drawable.white8, R.drawable.white9, R.drawable.white10, R.drawable.white11, R.drawable.white12, R.drawable.white13, R.drawable.white14, R.drawable.white15 }; // choice of tiles public static int[] choose = { R.drawable.choose0, R.drawable.choose1, R.drawable.choose2, R.drawable.choose3, R.drawable.choose4, R.drawable.choose5 }; // choice of tiles public static int[] chosen = { R.drawable.chosen0, R.drawable.black1, R.drawable.black5, R.drawable.black9, R.drawable.black11, R.drawable.black15 }; // choice of colours selected public static int [] colourSel = { R.drawable.colx1, R.drawable.colx2, R.drawable.colx3, R.drawable.colx4, R.drawable.colx5, R.drawable.colx6 }; // choice of colours not selected public static int[] colourNot = { R.drawable.col1, R.drawable.col2, R.drawable.col3, R.drawable.col4, R.drawable.col5, R.drawable.col6 }; // where joins are public static int [] nJoin = {0,0,0,1,0,0,0,1,1,0,1,0,1,1,1,1}; public static int [] eJoin = {0,0,0,0,1,1,0,0,1,1,0,1,0,1,1,1}; public static int [] sJoin = {0,1,0,0,0,1,1,0,0,0,1,1,1,0,1,1}; public static int [] wJoin = {0,0,1,0,0,0,1,1,0,1,0,1,1,1,0,1}; }


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

package com.edkins.celticknots2; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.GridView; import android.widget.ImageView; public class ImageType extends BaseAdapter { private AppCompatActivity mContext; public ImageType(AppCompatActivity c) {mContext = c;} public int getCount() {return 6;} public Object getItem(int position) {return null;} public long getItemId(int position) {return 0;} // create new ImageView for palette public View getView(int position, View convertView, ViewGroup parent) { ImageView imageView; if (convertView == null) { imageView = new ImageView(mContext); GridView typeV = (GridView) mContext.findViewById(R.id.typeView); int w = typeV.getWidth() / 12; imageView.setLayoutParams(new GridView.LayoutParams(w, w)); } else { imageView = (ImageView) convertView; } if (MainActivity.option==0) { if (MainActivity.knotPos == position) { imageView.setImageResource(MainActivity.chosen[position]); } else {imageView.setImageResource(MainActivity.choose[position]);} } else if (MainActivity.option==1) { imageView.setImageResource(R.drawable.space); } else if (MainActivity.option==2) { if ((position+1) == MainActivity.col) { imageView.setImageResource(MainActivity.colourSel [position]); } else {imageView.setImageResource(MainActivity.colourNot [position]);} } return imageView; } }


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

package com.edkins.celticknots2; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.GridView; import android.widget.ImageView; 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() / MainActivity.width; 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]; int col = MainActivity.colour[position]; if (col == 0) {imageView.setImageResource(MainActivity.black[sub]);} else if (col == 1) {imageView.setImageResource(MainActivity.red[sub]);} else if (col == 2) {imageView.setImageResource(MainActivity.blue[sub]);} else if (col == 3) {imageView.setImageResource(MainActivity.yellow[sub]);} else if (col == 4) {imageView.setImageResource(MainActivity.green[sub]);} else if (col == 5) {imageView.setImageResource(MainActivity.cyan[sub]);} else if (col == 6) {imageView.setImageResource(MainActivity.white[sub]);} return imageView; } }


Index to my other websites

© Jo Edkins 2016