commit f6062b23023eb21afb5bfa52be858202498d4308 Author: AndrewTrieu Date: Mon Jun 20 13:08:58 2022 +0700 Final diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..aa724b7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +/build +/captures +.externalNativeBuild +.cxx +local.properties diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..f063dcb --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Tic Tac Toe \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..fb7f4a8 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..a2d7c21 --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..3f2e1e1 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..babff97 --- /dev/null +++ b/README.md @@ -0,0 +1,19 @@ +# Tic-tac-toe app for Android +This project and repository are created for the course CT70A9120 Software Development Skills: Mobile of LUT University, Finland. The app is a Tic-tac-toe game, using a SQLite database to save details of each match (players' names, the winner, and time when the match finishes). The user can view all matches and delete them later. + +## Learning diary +The learning diary is included as a PDF in this repository. + +## Exercise materials +Exercice materials from the YouTube videos are in the folder Materials of this repository. + +## How to run the application? +Run the app using an Android Emulator, minimum API level 21. The application was tested on API level 32 during development, using USB debugging. An APK file is included in /app/build/outputs/apk/debug for easy installation. + +## Demonstration video +Link to be updated. + +## References +The logo of the app is from [PNGWing](https://www.pngwing.com/) and is used for educational purposes only in this project. +The Tic-tac-toe game is based on the Tic-tac-toe series of [Practical Coding](https://www.youtube.com/c/PracticalCoding "Practical Coding"). + diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..1fcb6ef --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,43 @@ +plugins { + id 'com.android.application' +} + +android { + compileSdk 32 + + defaultConfig { + applicationId "com.example.tictactoeapplut" + minSdk 21 + targetSdk 32 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + buildFeatures { + viewBinding true + } +} + +dependencies { + + implementation 'androidx.appcompat:appcompat:1.3.0' + implementation 'com.google.android.material:material:1.4.0' + implementation 'androidx.constraintlayout:constraintlayout:2.0.4' + implementation 'androidx.navigation:navigation-fragment:2.3.5' + implementation 'androidx.navigation:navigation-ui:2.3.5' + testImplementation 'junit:junit:4.13.2' + androidTestImplementation 'androidx.test.ext:junit:1.1.3' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' +} \ No newline at end of file diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/app/src/androidTest/java/com/example/tictactoeapplut/ExampleInstrumentedTest.java b/app/src/androidTest/java/com/example/tictactoeapplut/ExampleInstrumentedTest.java new file mode 100644 index 0000000..4daf416 --- /dev/null +++ b/app/src/androidTest/java/com/example/tictactoeapplut/ExampleInstrumentedTest.java @@ -0,0 +1,26 @@ +package com.example.tictactoeapplut; + +import android.content.Context; + +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +/** + * Instrumented test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); + assertEquals("com.example.tictactoeapplut", appContext.getPackageName()); + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..6198312 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/ic_launcher-playstore.png b/app/src/main/ic_launcher-playstore.png new file mode 100644 index 0000000..38fe06f Binary files /dev/null and b/app/src/main/ic_launcher-playstore.png differ diff --git a/app/src/main/java/com/example/tictactoeapplut/Board.java b/app/src/main/java/com/example/tictactoeapplut/Board.java new file mode 100644 index 0000000..14c3560 --- /dev/null +++ b/app/src/main/java/com/example/tictactoeapplut/Board.java @@ -0,0 +1,197 @@ +package com.example.tictactoeapplut; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; + +import androidx.annotation.Nullable; + +public class Board extends View { + + private final int boardColor; + private final int XColor; + private final int OColor; + private final int winColor; + private int cellSize = getWidth()/3; + private final Paint paint = new Paint(); + private final Move game; + private boolean winLine = false; + + public Board(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + game = new Move(context); + + TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.Board,0,0); + + try { + boardColor = a.getInteger(R.styleable.Board_boardColor, 0); + XColor = a.getInteger(R.styleable.Board_XColor, 0); + OColor = a.getInteger(R.styleable.Board_OColor, 0); + winColor = a.getInteger(R.styleable.Board_winColor, 0); + + } finally { + a.recycle(); + } + } + + @Override + protected void onMeasure(int width, int height) { + super.onMeasure(width, height); + + int size = Math.min(getMeasuredWidth(), getMeasuredHeight()); + cellSize = size/3; + + setMeasuredDimension(size, size); + } + + @Override + protected void onDraw(Canvas canvas) { + paint.setStyle(Paint.Style.STROKE); + paint.setAntiAlias(true); + + drawBoard(canvas); + drawMove(canvas); + + if (winLine) { + paint.setColor(winColor); + drawWinLine(canvas); + + } + } + + @SuppressLint("ClickableViewAccessibility") + @Override + public boolean onTouchEvent(MotionEvent event) { + float x = event.getX(); + float y = event.getY(); + + int action = event.getAction(); + if (action == MotionEvent.ACTION_DOWN) { + int row = (int) Math.ceil(y/cellSize); + int column = (int) Math.ceil(x/cellSize); + if (!winLine) { + if (game.updateBoard(row, column)) { + invalidate(); + if (game.winCheck()) { + winLine = true; + invalidate(); + } + if (game.getPlayer() % 2 == 0) { + game.setPlayer(game.getPlayer() - 1); + } else { + game.setPlayer(game.getPlayer() + 1); + } + } + } + + invalidate(); + + return true; + } + + return false; + } + + private void drawBoard(Canvas canvas) { + paint.setColor(boardColor); + paint.setStrokeWidth(16); + for (int x=1; x<3; x++) { + canvas.drawLine(cellSize*x, 0, cellSize*x, canvas.getWidth(), paint); + } + + for (int y=1; y<3; y++) { + canvas.drawLine(0, cellSize*y, canvas.getWidth(), cellSize*y, paint); + } + paint.setStrokeWidth(32); + canvas.drawLine(0,0,cellSize*3,0,paint); + paint.setStrokeWidth(32); + canvas.drawLine(0,cellSize*3,cellSize*3,cellSize*3,paint); + paint.setStrokeWidth(16); + canvas.drawLine(0,0,0,cellSize*3,paint); + paint.setStrokeWidth(16); + canvas.drawLine(cellSize*3,0,cellSize*3,cellSize*3,paint); + } + + private void drawMove(Canvas canvas) { + for (int r=0; r<3; r++) { + for (int c=0; c<3; c++) { + if (game.getBoard()[r][c]!=0) { + if (game.getBoard()[r][c]==1) { + drawX(canvas, r, c); + } else { + drawO(canvas, r, c); + } + } + } + } + } + + private void drawX(Canvas canvas, int row, int column) { + paint.setColor(XColor); + canvas.drawLine((float)((column+1)*cellSize - cellSize*0.1), (float)(row*cellSize+cellSize*0.1), (float)(column*cellSize+cellSize*0.1), (float)((row+1)*cellSize-cellSize*0.1), paint); + canvas.drawLine((float)(column*cellSize+cellSize*0.1), (float)(row*cellSize+cellSize*0.1), (float)((column+1)*cellSize-cellSize*0.1), (float)((row+1)*cellSize-cellSize*0.1), paint); + + } + + private void drawO(Canvas canvas, int row, int column) { + paint.setColor(OColor); + canvas.drawOval((float)(column*cellSize+cellSize*0.1), (float)(row*cellSize+cellSize*0.1), (float)(column*cellSize+cellSize-cellSize*0.1), (float)(row*cellSize+cellSize-cellSize*0.1), paint); + } + + private void drawHorizontal(Canvas canvas, int row, int column) { + canvas.drawLine(column, row*cellSize + cellSize/2, cellSize*3, row*cellSize+cellSize/2,paint); + } + + private void drawVertical(Canvas canvas, int row, int column) { + canvas.drawLine(column*cellSize+cellSize/2, row, column*cellSize+cellSize/2, cellSize*3,paint); + } + + private void drawSlopeUp(Canvas canvas) { + canvas.drawLine(0, cellSize*3, cellSize*3, 0 ,paint); + } + + private void drawSlopeDown(Canvas canvas) { + canvas.drawLine(0, 0, cellSize*3, cellSize*3 ,paint); + } + + private void drawWinLine(Canvas canvas) { + int row = game.getWinType()[0]; + int column = game.getWinType()[1]; + + switch (game.getWinType()[2]) { + case 1: + drawHorizontal(canvas, row, column); + break; + case 2: + drawVertical(canvas, row, column); + break; + case 3: + drawSlopeDown(canvas); + break; + case 4: + drawSlopeUp(canvas); + break; + } + } + + public void setUp(Button again, Button home, TextView display, String[] names) { + game.setAgain(again); + game.setHome(home); + game.setTurn(display); + if (!names[0].equals("") && !names[1].equals("")){ + game.setNames(names); + } + } + + public void resetGame() { + game.resetBoard(); + winLine = false; + } +} diff --git a/app/src/main/java/com/example/tictactoeapplut/CustomAdapter.java b/app/src/main/java/com/example/tictactoeapplut/CustomAdapter.java new file mode 100644 index 0000000..17ed1cd --- /dev/null +++ b/app/src/main/java/com/example/tictactoeapplut/CustomAdapter.java @@ -0,0 +1,66 @@ +package com.example.tictactoeapplut; + +import android.content.Context; +import android.content.Intent; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.TextView; + +import java.util.ArrayList; + +public class CustomAdapter extends BaseAdapter { + private static final String TAG = "CustomAdapter"; + Context context; + ArrayList name; + ArrayList winner; + ArrayList time; + + public CustomAdapter(Context context, ArrayList name, ArrayList winner, ArrayList time) { + this.context = context; + this.name = name; + this.winner = winner; + this.time = time; + } + + @Override + public int getCount() { + return name.size(); + } + + @Override + public Object getItem(int position) { + return null; + } + + @Override + public long getItemId(int position) { + return 0; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + convertView = inflater.inflate(R.layout.list_item,parent,false); + TextView txtName, txtWin, txtTime; + + txtName = convertView.findViewById(R.id.txt_name); + txtWin = convertView.findViewById(R.id.txt_win); + txtTime = convertView.findViewById(R.id.txt_time); + txtName.setText(name.get(position)); + txtWin.setText(winner.get(position)); + txtTime.setText(time.get(position)); + convertView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent editScreenIntent = new Intent(context, EditDataActivity.class); + editScreenIntent.putExtra("time",txtTime.getText().toString()); + editScreenIntent.putExtra("players", txtName.getText().toString()); + editScreenIntent.putExtra("winner", txtWin.getText().toString()); + context.startActivity(editScreenIntent); + } + }); + return convertView; + } +} diff --git a/app/src/main/java/com/example/tictactoeapplut/DatabaseHelper.java b/app/src/main/java/com/example/tictactoeapplut/DatabaseHelper.java new file mode 100644 index 0000000..eac4f3c --- /dev/null +++ b/app/src/main/java/com/example/tictactoeapplut/DatabaseHelper.java @@ -0,0 +1,64 @@ +package com.example.tictactoeapplut; + +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; + +public class DatabaseHelper extends SQLiteOpenHelper { + + private static final String TABLE_NAME = "record"; + private static final String COL1 = "players"; + private static final String COL2 = "winner"; + private static final String COL3 = "time"; + + + public DatabaseHelper(Context context) { + super(context, TABLE_NAME, null, 1); + } + + @Override + public void onCreate(SQLiteDatabase db) { + String createTable = "CREATE TABLE " + TABLE_NAME + " (ID INTEGER PRIMARY KEY AUTOINCREMENT, " + + COL1 +" TEXT, " + COL2 + " TEXT, " + COL3 + " TEXT)"; + db.execSQL(createTable); + } + + @Override + public void onUpgrade(SQLiteDatabase db, int i, int i1) { + db.execSQL("DROP IF TABLE EXISTS " + TABLE_NAME); + onCreate(db); + } + + public boolean addData(String players, String winner, String time) { + SQLiteDatabase db = this.getWritableDatabase(); + ContentValues contentValues = new ContentValues(); + contentValues.put(COL1, players); + contentValues.put(COL2, winner); + contentValues.put(COL3, time); + + long result = db.insert(TABLE_NAME, null, contentValues); + + if (result == -1) { + return false; + } else { + return true; + } + } + + public Cursor getData(){ + SQLiteDatabase db = this.getWritableDatabase(); + String query = "SELECT * FROM " + TABLE_NAME; + Cursor data = db.rawQuery(query, null); + return data; + } + + public void deleteMatch(String time){ + SQLiteDatabase db = this.getWritableDatabase(); + String query = "DELETE FROM " + TABLE_NAME + " WHERE " + + COL3 + " = '" + time + "'"; + db.execSQL(query); + } + +} diff --git a/app/src/main/java/com/example/tictactoeapplut/EditDataActivity.java b/app/src/main/java/com/example/tictactoeapplut/EditDataActivity.java new file mode 100644 index 0000000..1d537d7 --- /dev/null +++ b/app/src/main/java/com/example/tictactoeapplut/EditDataActivity.java @@ -0,0 +1,57 @@ +package com.example.tictactoeapplut; + +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; +import android.widget.Toast; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +public class EditDataActivity extends AppCompatActivity { + + private Button btnDelete; + private TextView txtPlayers, txtWinner, txtTime; + + DatabaseHelper mDatabaseHelper; + + private String selectedPlayers, selectedWinner, selectedTime; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.edit_data_layout); + btnDelete = (Button) findViewById(R.id.btnDelete); + txtPlayers = (TextView) findViewById(R.id.txtPlayers); + txtWinner = (TextView) findViewById(R.id.txtWinner); + txtTime = (TextView) findViewById(R.id.txtTime); + mDatabaseHelper = new DatabaseHelper(this); + + Intent receivedIntent = getIntent(); + + selectedPlayers = receivedIntent.getStringExtra("players"); + selectedWinner = receivedIntent.getStringExtra("winner"); + selectedTime = receivedIntent.getStringExtra("time"); + + txtPlayers.setText(selectedPlayers); + txtWinner.setText(selectedWinner); + txtTime.setText(selectedTime); + + btnDelete.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + mDatabaseHelper.deleteMatch(selectedTime); + txtPlayers.setText(""); + txtWinner.setText(""); + txtTime.setText(""); + toaster(); + } + }); + + } + private void toaster(){ + Toast.makeText(this, "Match removed", Toast.LENGTH_SHORT).show(); + } +} diff --git a/app/src/main/java/com/example/tictactoeapplut/Game.java b/app/src/main/java/com/example/tictactoeapplut/Game.java new file mode 100644 index 0000000..928ca3b --- /dev/null +++ b/app/src/main/java/com/example/tictactoeapplut/Game.java @@ -0,0 +1,46 @@ +package com.example.tictactoeapplut; + +import androidx.appcompat.app.AppCompatActivity; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; + +public class Game extends AppCompatActivity { + private Board board; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_game); + Button again = findViewById(R.id.button6); + Button home = findViewById(R.id.button5); + TextView turn = findViewById(R.id.textView5); + again.setVisibility(View.GONE); + home.setVisibility(View.GONE); + String[] names = getIntent().getStringArrayExtra("PLAYERS"); + assert names != null; + if (names[0].equals("")){ + + turn.setText((String)("Player 1's turn")); + }else{ + turn.setText((String)(names[0] + "'s turn")); + } + board = findViewById(R.id.board); + + board.setUp(again, home, turn, names); + } + + public void againClick(View view) { + board.resetGame(); + board.invalidate(); + } + + public void homeClick(View view) { + Intent intent = new Intent(this, MainActivity.class); + startActivity(intent); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/tictactoeapplut/ListDataActivity.java b/app/src/main/java/com/example/tictactoeapplut/ListDataActivity.java new file mode 100644 index 0000000..71255c7 --- /dev/null +++ b/app/src/main/java/com/example/tictactoeapplut/ListDataActivity.java @@ -0,0 +1,48 @@ +package com.example.tictactoeapplut; + +import android.database.Cursor; +import android.os.Bundle; +import android.util.Log; +import android.widget.ListView; +import android.widget.Toast; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +import java.util.ArrayList; + +public class ListDataActivity extends AppCompatActivity { + + private static final String TAG = "ListDataActivity"; + + DatabaseHelper mDatabaseHelper; + + private ListView mListView; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.list_layout); + mListView = (ListView) findViewById(R.id.listView); + mDatabaseHelper = new DatabaseHelper(this); + + populateListView(); + } + + private void populateListView() { + Log.d(TAG, "populateListView: Displaying data in the ListView."); + + Cursor data = mDatabaseHelper.getData(); + ArrayList listPlayers = new ArrayList<>(); + ArrayList listWinner = new ArrayList<>(); + ArrayList listTime = new ArrayList<>(); + while(data.moveToNext()){ + + listPlayers.add(data.getString(1)); + listWinner.add(data.getString(2)); + listTime.add(data.getString(3)); + } + CustomAdapter adapter = new CustomAdapter(this, listPlayers, listWinner, listTime); + mListView.setAdapter(adapter); + } +} diff --git a/app/src/main/java/com/example/tictactoeapplut/MainActivity.java b/app/src/main/java/com/example/tictactoeapplut/MainActivity.java new file mode 100644 index 0000000..7c0df8a --- /dev/null +++ b/app/src/main/java/com/example/tictactoeapplut/MainActivity.java @@ -0,0 +1,50 @@ +package com.example.tictactoeapplut; + +import androidx.appcompat.app.AppCompatActivity; + +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.util.Log; +import android.view.View; +import android.widget.TextView; + +public class MainActivity extends AppCompatActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + TextView description = (TextView) findViewById(R.id.textView2); + TextView link = (TextView) findViewById(R.id.textView3); + description.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Uri lut = Uri.parse((String)"https://www.lut.fi/en"); + Intent toLUT = new Intent(Intent.ACTION_VIEW, lut); + if (toLUT.resolveActivity(getPackageManager()) != null) { + startActivity(toLUT); + } + } + }); + link.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Uri github = Uri.parse((String)"https://github.com/AndrewTrieu/tictactoeapp"); + Intent toGitHub = new Intent(Intent.ACTION_VIEW, github); + if (toGitHub.resolveActivity(getPackageManager()) != null) { + startActivity(toGitHub); + } + } + }); + } + + public void startClick(View view){ + Intent intent = new Intent(this, Prepare.class); + startActivity(intent); + } + public void recordClick(View view){ + Intent intent = new Intent(this, ListDataActivity.class); + startActivity(intent); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/tictactoeapplut/Move.java b/app/src/main/java/com/example/tictactoeapplut/Move.java new file mode 100644 index 0000000..f50c197 --- /dev/null +++ b/app/src/main/java/com/example/tictactoeapplut/Move.java @@ -0,0 +1,147 @@ +package com.example.tictactoeapplut; + +import android.content.Context; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; + +import java.sql.Timestamp; +import java.text.SimpleDateFormat; +import java.util.Date; + + +public class Move { + private int[][] board; + private String[] names = {"Player 1", "Player 2"}; + private int[] winType = {-1, -1, -1}; + private Button again; + private Button home; + private TextView turn; + private int player = 1; + private static final SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss dd.MM.yyyy"); + + DatabaseHelper databaseHelper; + + Move(Context context) { + databaseHelper = new DatabaseHelper(context); + board = new int[3][3]; + for (int r=0; r<3; r++) { + for (int c=0; c<3; c++) { + board[r][c] = 0; + } + } + } + + public boolean updateBoard(int row, int column) { + if (board[row-1][column-1]==0) { + board[row-1][column-1] = player; + if (player == 1) { + turn.setText((String)(names[1]+"'s turn")); + } else { + turn.setText((String)(names[0]+"'s turn")); + } + return true; + } else { + return false; + } + } + + public boolean winCheck() { + boolean won = false; + + for (int r = 0; r < 3; r++) { + if (board[r][0] == board[r][1] && board[r][0] == board[r][2] && board[r][0] != 0) { + winType = new int[] {r, 0, 1}; + won = true; + break; + } + } + for (int c = 0; c < 3; c++) { + if (board[0][c] == board[1][c] && board[0][c] == board[2][c] && board[0][c] != 0) { + winType = new int[] {0, c, 2}; + won = true; + break; + } + } + if (board[0][0]==board[1][1] && board[0][0]==board[2][2] && board[0][0]!=0) { + winType = new int[] {0, 2, 3}; + won = true; + } + if (board[2][0]==board[1][1] && board[2][0]==board[0][2] && board[2][0]!=0) { + winType = new int[] {2, 2, 4}; + won = true; + } + + int boardFilled = 0; + for (int r=0; r<3; r++) { + for (int c=0; c<3; c++) { + if (board[r][c]!=0){ + boardFilled+=1; + } + } + } + + if (won) { + again.setVisibility(View.VISIBLE); + home.setVisibility(View.VISIBLE); + turn.setText((String)(names[player-1]+" won!")); + Timestamp timestamp = new Timestamp(System.currentTimeMillis()); + databaseHelper.addData(names[0]+" vs "+names[1], names[player-1], sdf.format(timestamp)); + return true; + } else if(boardFilled==9){ + again.setVisibility(View.VISIBLE); + home.setVisibility(View.VISIBLE); + turn.setText((String)("Tie game!")); + Timestamp timestamp = new Timestamp(System.currentTimeMillis()); + databaseHelper.addData(names[0]+" vs "+names[1], "Tie", sdf.format(timestamp)); + return false; + } else { + return false; + } + } + + public void resetBoard() { + for (int r=0; r<3; r++) { + for (int c=0; c<3; c++) { + board[r][c] = 0; + } + } + player = 1; + again.setVisibility(View.GONE); + home.setVisibility(View.GONE); + turn.setText((String)(names[0]+"'s turn")); + } + + public void setAgain(Button again) { + this.again = again; + } + + public void setHome(Button home) { + this.home = home; + } + + public void setTurn(TextView turn) { + this.turn = turn; + } + + public void setNames(String[] names) { + this.names = names; + } + + public int[][] getBoard() { + return board; + } + + public void setPlayer(int player) { + this.player = player; + } + + public int getPlayer() { + return player; + } + + public int[] getWinType() { + return winType; + } + +} diff --git a/app/src/main/java/com/example/tictactoeapplut/Prepare.java b/app/src/main/java/com/example/tictactoeapplut/Prepare.java new file mode 100644 index 0000000..30b6f4f --- /dev/null +++ b/app/src/main/java/com/example/tictactoeapplut/Prepare.java @@ -0,0 +1,29 @@ +package com.example.tictactoeapplut; + +import androidx.appcompat.app.AppCompatActivity; + +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import android.widget.EditText; + +public class Prepare extends AppCompatActivity { + private EditText player1; + private EditText player2; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_prepare); + player1 = findViewById(R.id.editTextTextPersonName4); + player2 = findViewById(R.id.editTextTextPersonName3); + } + public void playClick(View view) { + String player1Name = player1.getText().toString(); + String player2Name = player2.getText().toString(); + + Intent intent = new Intent(this, Game.class); + intent.putExtra("PLAYERS", new String[] {player1Name, player2Name}); + startActivity(intent); + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/blue.xml b/app/src/main/res/drawable/blue.xml new file mode 100644 index 0000000..ce9dce5 --- /dev/null +++ b/app/src/main/res/drawable/blue.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/button.xml b/app/src/main/res/drawable/button.xml new file mode 100644 index 0000000..3c3a6f6 --- /dev/null +++ b/app/src/main/res/drawable/button.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..07d5da9 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/logo.png b/app/src/main/res/drawable/logo.png new file mode 100644 index 0000000..2291f6d Binary files /dev/null and b/app/src/main/res/drawable/logo.png differ diff --git a/app/src/main/res/drawable/red.xml b/app/src/main/res/drawable/red.xml new file mode 100644 index 0000000..dc7b941 --- /dev/null +++ b/app/src/main/res/drawable/red.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/yellow.xml b/app/src/main/res/drawable/yellow.xml new file mode 100644 index 0000000..e48d6ba --- /dev/null +++ b/app/src/main/res/drawable/yellow.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_game.xml b/app/src/main/res/layout/activity_game.xml new file mode 100644 index 0000000..67ca370 --- /dev/null +++ b/app/src/main/res/layout/activity_game.xml @@ -0,0 +1,75 @@ + + + + + + + +