Android App ep.102

My Network Reporter v.2

For this project we are going to be recreating the network reporter application in Kotlin to look at the advantages and uniqueness Kotlin can provide.

Previous application utilizing java: Android App ep.101

Application Purpose:

This will remain the same as the last application….

We want to discern if transmitting a file of a size A across a network with a speed B gives us a reasonable time in seconds.

Our size of the file size is measured in MiB and our network speed is measured in Mbps.

We know that 1 B = 8 b; 1 MiB = 220 B; 1 Mbps = 106 bps.

Video to view in action: https://youtu.be/JUkxk5NhutM

activity_main.xml  Layout


This will remain the same as well since we just want to look at the benefits of Kotlin to Java.

Screen Shot 2018-10-15 at 8.44.27 AM

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">

    <TextView
        android:id="@+id/textView"
        android:layout_width="96dp"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:paddingHorizontal="10dp"
        android:text="@string/file_size_label"
        android:textAlignment="center"
        android:textAllCaps="false"
        android:textSize="14sp" />

    <EditText
        android:id="@+id/fileSizeInput"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="@string/file_input_hint"
        android:inputType="number" />

</LinearLayout>

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">

    <TextView
        android:id="@+id/networkSpeedLabel"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text="@string/network_label"
        android:textAlignment="center"
        android:textSize="14sp" />

    <EditText
        android:id="@+id/networkSpeedInput"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="@string/network_hint"
        android:inputType="number" />
</LinearLayout>

<TextView
    android:id="@+id/resultDisplay"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="Input is needed for both File Size and Network Speed to estimate time"
    android:textAlignment="center"
    android:textColor="@android:color/black"
    android:textSize="18sp" />

On our Kotlin side…


package com.amsuarez.mynetworkreporter

import android.app.Activity
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.widget.EditText
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

    fun EditText.changed() {
       this.addTextChangedListener(object: TextWatcher {
            override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
            override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {
                if (fileSizeInput.text.toString() == "" || networkSpeedInput.text.toString() == "") {
                    resultDisplay.text = "Input is needed for both File Size and Network Speed to estimate time"
                } else {
                    val myb = Integer.parseInt(fileSizeInput.text.toString()).toDouble() * Math.pow(2.0, 20.0) * 8.0
                    val mybps = Integer.parseInt(networkSpeedInput.text.toString()) * Math.pow(10.0, 6.0)
                    resultDisplay.setText(String.format("%.1f", myb / mybps) + " seconds")
                }
            }
            override fun afterTextChanged(s: Editable) {}
        })
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        fileSizeInput.changed()
        networkSpeedInput.changed()
    }
}

Here we utilized some really cool features that Kotlin provides us with.

Extension Functions:

We utilized these to extend upon the EditText class to allow us to run a text watcher object in any EditText. This gives us a very clean call in our onCreate fun increasing readability.

Where are the findViewByIds? 👀

Kotlin provides a feature that allows us to reference straight out of our activities.

It is done by importing:

 import kotlinx.android.synthetic.main.activity_main.*

This allows us to no longer need to call findViewById and instead we can reference directly into our activities.

Objects? 🤔

Here we use object as an anonymous class that inherits TextWatcher allowing us to override the TextWatcher without having to “formally declare a new class”.

For more on Objects: https://kotlinlang.org/docs/reference/object-declarations.html

 

Mancala-AI

Mancala-AI

By Matt Corrente, Paul Miller, Luigi Sanchez, and Austin Suarez

Project Link: https://github.com/138paulmiller/Mancala-AI-Bot/blob/master/README.md

Summary

The Mancala AI is a project that I got to work on with some very talented programmers (Matt Corrente, Paul Miller, and Luigi Sanchez). Our project was to use artificial intelligence in a unique way. Although AI for games has been done we thought it would be interesting to do a study on how each AI algorithm can compete against one another. We built out it out three different AI algorithms ( Min-max with Alpha beta, Monte Carlo, and Evolutionary) to run on a Flask app.

About Mancala

“It’s an ancient family of board games, and there are numerous variants. Many different forms of Mancala are played across Africa, though the game may originally have come from ancient Sumeria.”[1]

Mancala is a two player turn-based board game.The goal is to capture the most beans and stones into your side.

Since Mancala is a game with a clear set of rules it allows for each AI to calculate a path to victory fairly. By fairly, we mean that some variations of this game are not perfect and allow for an extremely calculate the first move that is capable of ending the game.

 

Rules

  1. The Mancala board is made up of two rows of six holes, or pits, each.
  2. Four pieces—marbles, chips, or stones—are placed in each of the 12 holes.
  3. Each player has a store (called a Mancala) to the right side of the Mancala board.
  4. The game begins with one player picking up all of the pieces in any one of the holes on his side.
  5. Moving counter-clockwise, the player deposits one of the stones in each hole until the stones run out.
  6. If you run into your own store, deposit one piece in it. If you run into your opponent’s store, skip it.
  7. If the last piece you drop is in your own store, you get a free turn.
  8. If the last piece you drop is in an empty hole on your side, you capture that piece and any pieces in the hole directly opposite.
  9. Always place all captured pieces in your store.
  10. The game ends when all six spaces on one side of the Mancala board are empty.
  11. The player who still has pieces on his side of the board when the game ends capture all of those pieces.
  12. Count all the pieces in each store. The winner is the player with the most pieces. [2]

Algorithms

Mancala represents a decision problem since each player must decide on a single move to make. Each of our AI agents makes use of varying algorithms for decision making.

We used:

  • Minimax with Alpha-Beta Pruning
  • Monte-Carlo Tree Search
  • Evolutionary Algorithm with binary encoded moves

The algorithms we used vary in the method of deciding. For example, our Minimax, Monte-Carlo and Evolutionary algorithms make use of traversing the current game tree. However, both searching algorithms use different heuristics to limit the state space being search. The state space for an entire game is very large, and running an exhaustive search on the entire game tree will run in about O(6^n) time. Where n is a number of total turns, where each player has at most 6 choices. A naive exhaustive searching algorithm for this is completely inefficient, so adding a maximum lookahead depth allows us to bound the search space for our algorithms making them run in a reasonable enough time to play against.

 

Heuristics

All our algorithms make use of a variable heuristic function. This function analyzes the current state of the board to help the AI make the best possible decision. This heuristic can be used to:

  • Maximize AI’s score
  • Maximize the difference between the AI and players score
  • Maximize the number of pebbles on the AI side
  • Maximize the difference between the number of pebbles on AI side from player’s side

Or a weighted polynomial of the above (x = score, p = pebble diff = x+p*0.3)

Modifying the evaluation heuristic also changes the difficulty of the AI. For instance, in the Minimax algorithm, evaluating the score performs much better than evaluating a number of pebbles on each side. Also, measuring the relative score between the player and the AI performs better than just maximizing the AI. The reasoning behind this would be that the AI not only maximizes his own score but also makes sure that the next best move for the player will be far lower than the AI’s score. So, it would preference 9 vs 3 over 10 vs 8.

 

Playability

Each of our algorithms performs differently. The Minimax algorithm with Alpha-Beta pruning is a more exhaustive searching making it much slower but is also much more difficult to beat. With a turn lookahead depth of around 6-8, the AI is quick enough to play and very difficult to beat. However, if the lookahead is not set and the AI searches the entire game tree, the AI will be unbeatable, however, due to the time complexity of the game tree, the AI takes far too long to decide on a move even with alpha-beta pruning. So, both Monte-Carlo and Evolutionary Algorithm decision-making approaches are much more user-friendly. The Monte-Carlo algorithm makes uses of a probabilistic adversarial decision making, which chooses the other players most likely move. This allows the algorithm to be far less exhaustive making it capable of making more human-like decisions, since the enemy may not always choose the predicted move. The Evolutionary algorithm makes use of binary programs that encode possible moves for the AI. The populations are initialized randomly and evolved using probabilistic mutation and crossover. Each population is evaluated by testing the heuristic for each next potential move, and the moves with the highest scores are more likely to be chosen for reproduction.

Conclusion

This was a very interesting project. Since the game tree is simple enough to visualize, yet results in an exponential explosion of possible game states. Each AI plays the game differently thus it is very interesting to see the result from the AI vs AI.

Work Cited

[1] https://www.thespruce.com/how-to-play-mancala-409424

[2] https://www.thespruce.com/how-to-play-mancala-409424

Deck of Cards Trick

Here is a great critical thinking problem that I heard.

Scenario:

You are blind folded and cannot see.

I hand you a deck of cards telling you that a 5 are faced up and placed randomly in the deck (the rest are face down)  and ask you to split the group of cards into two groups such that each group has the same amount of face up cards.

This problem is great because one it forces you to think outside of the box and since the question itself can be easily represented in a computer science context.

 

(please try before just looking at solution, there is a way to split with 100% accuracy)

WARNING SPOILERS  SOLUTION BELOW!!!! 

 

 

 

Explanation:

The amount of cards in the deck doesn’t matter nor does the position of the cards face up in the deck. We can represent the problem as an array with 1s (face up ) and 0s (faced down). We can assume that based on the questions the groups don’t need to have the original amount of face up cards (5 is odd and you can’t really split it up evenly). Thus we must think how can to place the two groups separately.  If you take the amount of flipped cards from anywhere in the deck and invert them no matter their current orientation and take them placing it into group one and the rest into group two you will have met the problem conditions and have the correct solution.

#include <iostream>
#include <random>

using namespace std;
 //Compiler version g++ 6.3.0

int main()
 {
 	int deck[52];
 	int temp;
 	int flipCards = rand()%52+1;

	int* groupOne;
	int* groupTwo;

	for(int index =0; index < 52; index++)
 	{
 		deck[index] = 0;
 	}
	for(int index = 0; index < flipCards; index++)
	{

		do{
 			temp = rand()%52;
 		}while(1 == deck[temp]);
 		deck[temp]=1;
 	}
	groupOne = new int[flipCards]();
	groupTwo = new int[52-flipCards]();

	for(int index =0; index < 52; index++)
	{
		cout << deck[index] << endl;
	}
 	cout << endl;
	for(int index = 0; index < flipCards; index++)
 	{
		deck[index]= abs(deck[index]-1);
		groupOne[index] = deck[index];
 		cout << groupOne[index];
	}
	 cout << endl;

	for(int index = flipCards; index < 52; index++)
	{
		groupTwo[index] = deck[index];
 		cout << groupTwo[index];
 	}
 	cout << endl;
	return 0;
 }

Electronics Shop

This Hackerrank problem deals with combinations.

The problem:

Sketch

import sys

def getMoneySpent(keyboards, drives, s):
 combo = -1
 for k in keyboards:
 	for d in drives: 
 		if (k+d) > combo and (k+d) <= s:
 			combo = k+d
 
 return str(combo)
 
s,n,m = input().strip().split(' ')
s,n,m = [int(s),int(n),int(m)]
keyboards = list(map(int, input().strip().split(' ')))
drives = list(map(int, input().strip().split(' ')))
# The maximum amount of money she can spend on a keyboard and USB drive, or -1 if she can't purchase both items
moneySpent = getMoneySpent(keyboards, drives, s)
print(moneySpent)

This problem is pretty straight forward. I used to for loops to cycle through each list.

Another way to do it might be to sort the list eliminate the clearly overly expensive items that are over s and delete those that are  duplicates to cycle through less elements. This might help for very big lists.

 

The Day of the Programmer

This Hackerrank problem asks you given the year, the 256 date of that year according to the Russian Calendar.

Screen Shot 2017-11-05 at 5.35.44 PM

The Code:

import sys

def solve(year):
    months = [31,28,31,30,31,30,31,31]
    
    if year > 1918:
        if year%400 == 0 or (year%4 == 0 and year%100 != 0):
            months[1] = 29
            tmp = sum(months)
            day = 256-tmp
        else:
            tmp = sum(months)
            day = 256-tmp
    elif year == 1918:
        months[1] = 15
        tmp = sum(months)
        day = 256-tmp
    else:
        if year%4 == 0:
            months[1] = 29
            tmp = sum(months)
            day = 256-tmp
        else:
            tmp = sum(months)
            day = 256-tmp
    

   return (str(day) + '.' + "09" + '.' + str(year))
year = int(input().strip())
result = solve(year)
print(result)

For this problem, I set the number of days in the months from January through August into an array and summed them together. After which I subtracted from 256 and got the day. To get the variations in days I altered the month of February based on the calendar system.

Developer Aside:

I took the easy way out in displaying the month since in the Russian calendar system (regardless of the year) the 256 day lands in September.

 

Kangaroo

This is another easy Hackerrank question, Kangaroo.

This problem takes a high school math problem of will one car ever catch another, but instead of cars we are talking kangaroos

kangaroo

def kangaroo(x1, v1, x2, v2):
 if x1 > x2:
    temp = x1
    x1 = x2
    x2 = temp
    temp = v1
    v1 = v2
    v2 = temp 
 
 if v1 <= v2:
    return "NO"
 
 while(x1 < x2):
    x1+=v1
    x2+=v2
 if(x1 == x2):
   return "YES"
 else:
   return "NO"

#given
x1, v1, x2, v2 = input().strip().split(' ')
x1, v1, x2, v2 = [int(x1), int(v1), int(x2), int(v2)]
result = kangaroo(x1, v1, x2, v2)
print(result)

For this problem I set x2 to always be further than x1 by creating a swap condition. After I check if the kangaroo at x1 has a velocity higher than kangaroo at x2 if it isn’t they will never meet. Finally I cycle through until x1 is no longer less than x2.

Mental Note

Mental Note was a note taking application (also the first UWP)  I built. I wanted to try and understand MSA login and async file storage. It was a fun little side project, there are definitely some bugs and design choices I would do differently now. In the end I walked away understanding the ideas of login and file storage for UWP applications.

The project is in my GitHub: GitHub.com/amsuarez01

Here are some screen shots.

This slideshow requires JavaScript.

Habit Hamster

Habit Hamster is a application that will keep track of habits like a reminder list. Current habit tracking apps do not provide a means for users to visually see progress. I am currently working on this in my Software Engineering class and am loving how awesome it is to make UWP applications.

It is currently on my GitHub: GitHub.com/amsuarez01 under Habit hamster.

Here are some Screen shots of the UWP side of development that I have been in charge of.

This slideshow requires JavaScript.

 

Quicksort

The Quick Sort was developed in the early 1960s, by Tony Hoarde, since it became one of the most common sorts. The algorithm performs an in-place comparison sort it utilizes very little extra memory on sorting the string. It has a worst case of O(n^2) and a best case of O(nlogn).

It is first going to select the pivot as the last number in the list

pivot = 58

Then it assigns lo = -1

For each number from 0 to pivot’s position

If a number in that list is less than the pivot number

Then lo is incremented

and it swaps the index number with the number at the lo position

If the number at the end of the list is less than the number at the lo+1 Position

then swap them

Code: step  example

41      67      34      0       69      24      78      58

swapping: 41 with 41

41      67      34      0       69      24      78      58

41      67      34      0       69      24      78      58

swapping: 67 with 34

41      34      67      0       69      24      78      58

swapping: 67 with 0

41      34      0       67      69      24      78      58

41      34      0       67      69      24      78      58

swapping: 67 with 24

41      34      0       24      69      67      78      58

41      34      0       24      69      67      78      58

swapping: 69 with 58

41      34      0       24      58      67      78      69

the pivot point is: 58

41      34      0       24      58      67      78      69

41      34      0       24      58      67      78      69

swapping: 41 with 0

0       34      41      24      58      67      78      69

swapping: 34 with 24

0       24      41      34      58      67      78      69

the pivot point is: 24

0       24      41      34      58      67      78      69

swapping: 41 with 34

0       24      34      41      58      67      78      69

the pivot point is: 34

swapping: 67 with 67

0       24      34      41      58      67      78      69

0       24      34      41      58      67      78      69

swapping: 78 with 69

0       24      34      41      58      67      69      78

the pivot point is: 69

0       24      34      41      58      67      69      78

 

#include “iostream”
#include “random”
using namespace std;
void quickSort(int list[8],int high,int low);
int partition(int list[8],int high,int low);
int main()
{
 int list[8];
 for(int index =0; index < 8; index++)
 {
    list[index] = rand()%100;
    cout << list[index] << ‘\t’;
 }
 cout << endl;
 quickSort(list,7,0);
 for(int index =0; index < 8; index++)
 {
    cout << list[index] << ‘\t’;
 }
 return 0;
}
void quickSort(int list[8],int high,int low)
{
 int temp;
 if(low < high)
 {
    temp = partition(list, high,low);
    cout << “the pivot point is: “ << list[temp] << endl;
    quickSort(list,temp1,low);
    quickSort(list, high, temp+1);
 }
};
int partition(int list[8],int high,int low)
{
 int pivot = list[high];
 int lo = low1;
 int temp;
 for(int index = low; index < high; index++)
 {
    if(list[index] < pivot)
    {
     lo+=1;
     cout << “swapping: “ << list[lo] << ” with “ << list[index] << endl;
     temp = list[lo];
     list[lo] = list[index];
     list[index] = temp;
    }
    for(int index =0; index < 8; index++)
    {
     cout << list[index] << ‘\t’;
    } cout << endl;
 }
 if(list[high] < list[lo+1])
 {
     cout << “swapping: “ << list[lo+1] << ” with “ << list[high] << endl;
    temp = list[lo+1];
    list[lo+1] = list[high];
    list[high] = temp;
 }
 for(int index =0; index < 8; index++)
 {
    cout << list[index] << ‘\t’;
 } cout << endl;
 return lo+1;
};