{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# C14008 Lesson 4: Julia Packages\n", "What's poppin' π₯ gang π¨βπ«, Cameron is coming in **_HOT_**π₯ππ§―𧨠with a class π« about packages π¦ and stuff π. He wrote this whole notebook π, but I've snuck this little bit of textβπΌ in right under β¬οΈ his nose ππΌ!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Presenting solutions\n", "\n", "Welcome back to class! Because there was no assigned homework, there are no assigned problems to present. So, solutions to any Euler problems completed over the past week are welcome to presented now. These include:\n", "\n", "- Euler 13\n", "- Euler 28\n", "- Euler 29\n", "- Euler 30\n", "- Euler 39" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## File I/O in Julia\n", "Often in Julia, you'll need to read in files to have data to work with, and there's a number of methods we can use to accomplish this. First, let's create a file and put some information in it." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Open a file for writing and write to it\n", "\n", "# Close the file so that changes are actually applied" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now, open the file again with another handler to read from it." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# opening the file with open\n", "\n", "# calling read to read from the file" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In fact, we can actually shortcut this process just by calling `read()` directly. `read()` understands we're talking about a file path and opens it for us." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# using read to read the file directly\n", "\n", "# using readlines to read in lines as an array\n", "\n", "# using readline to read one at a time\n", "\n", "# using eachline to create an interable" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Taking a moment to talk about Julia's `do` syntax\n", "\n", "Julia has a special syntax using a `do` block if you want to use a function as your first argument. Take the `map` function as an example, which takes an Array and a function to apply on that array." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "a = [1, 2, 3]\n", "\n", "# Applyng map function normally\n", "\n", "# Applying map function with do syntax" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This syntax actually works for any function with a `Function` as the first argument. Let's create a function below and use the `do` function to figure out what `f(5)` is." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "function runSomeMath(f::Function)\n", " println(\"Figuring out what f(5) is!\")\n", " return f(5)\n", "end" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "runSomeMath() do x\n", " # math function goes here\n", "end" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Using `open()` and `read()` with a `do` block\n", "The convenience of this method is that the file is automatically opened and closed for us within the block, giving us a scoped area to deal with the file and close it once we're done. This is similar to opening a file with a `with` statement in Python." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# opening a file for writing with do\n", "\n", "# reading a file with do" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Briefly covering the `Random` module\n", "because it might come in handy at some point to you. One thing we can do with Random is generate random lists of numbers using the `rand(type or set[, dims])` function." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "using Random\n", "\n", "# generating random decimals\n", "\n", "# generating a random list\n", "\n", "# generating a random value in a ranges" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Another thing we can do with the `Random` module is shuffle lists." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "ajr = [\"Adam\", \"Jack\", \"Ryan\"] # or Aaron, Johnson, Rodger (no)\n", "\n", "# shuffling a list\n", "\n", "# shuffling a range" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## How to log in Julia\n", "To write log messages, we're going to use the `Logging` module. Julia describes the `Logging` module as:\n", "> The `Logging` module provides a way to record the history and progress of a computation as a log of events.\n", "\n", "There's a couple different logging \"levels\" as defined by Julia that explain how serious a problem is, or what the purpose of the log message is:\n", "> The _log level_ is a broad category for the message that is used for early filtering. There are several standard levels of type [`LogLevel`](https://docs.julialang.org/en/v1/stdlib/Logging/#Logging.LogLevel); user-defined levels are also possible. Each is distinct in purpose:\n", ">\n", "> - `Debug` is information intended for the developer of the program. These events are disabled by default.\n", "> - `Info` is for general information to the user. Think of it as an alternative to using `println` directly.\n", "> - `Warn` means something is wrong and action is likely required but that for now the program is still working.\n", "> - `Error` means something is wrong and it is unlikely to be recovered, at least by this part of the code. Often this log-level is unneeded as throwing an exception can convey all the required information.\n", "\n", "For your purposes, you're probably going to want to use `@info` most of the time, or maybe `@warn` or `@error` if you wanted to catch someone's attention." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "using Logging\n", "\n", "# Logging with @info\n", "\n", "# Displaying variables and named parameters\n", "\n", "# Logging with @warn and @error" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Writing and running tests in Julia\n", "\n", "Before we get to tests, there's one quick and dirty way in Julia to have code throw an error if something fails, which is `@assert`." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# using @assert if true\n", "\n", "# what happens when @assert is false" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To write and run tests, we're going to use the `Test` module. Julia describes the `Test` module as:\n", "> The `Test` module provides simple _unit testing_ functionality. Unit testing is a way to see if your code is correct by checking that the results are what you expect. It can be helpful to ensure your code still works after you make changes, and can be used when developing as a way of specifying the behaviors your code should have when complete.\n", "\n", "First, let's import the `Test` module." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "using Test" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The most basic thing we can do with the test module is check whether a statement is true or not by using the `@test` macro." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# write @test" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can also check whether a function under a set of conditions throws a specific error using `@test_throws Error function()`." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# write @test_throws" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can check that a function logs a certain message using a certain log level with `@test_logs (:level, \"message\") function()`." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "function iLog(variable)\n", " @info \"You gave me $variable\"\n", "end\n", "\n", "# write @test_logs" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now, let's create a function to check who won a game of TicTacToe, using a 3Γ3 matrix to represent a game. 1s will represent one player while 2s will represent the other. 0s represent unplayed spaces." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "using LinearAlgebra\n", "\n", "function ticTacToeCheck(board::Array{Int,2})\n", " size(board) == (3,3) || throw(DimensionMismatch(\"Board size mismatch\"))\n", " winSeqs = vcat([board[n, :] for n in 1:3], [board[:, n] for n in 1:3]) # check rows and columns\n", " winSeqs = vcat(winSeqs, [diag(board)], [diag(board[:, end:-1:1])]) # add diagonals\n", " if [1,1,1] in winSeqs\n", " return 1\n", " elseif [2,2,2] in winSeqs\n", " return 2\n", " else\n", " return 0\n", " end\n", "end" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now, we're going to use the `@testset` functionality to check our ticTacToe checker to see if it works." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "@testset \"Tic Tac Toe\" begin\n", " win1 = [1 0 2\n", " 1 2 0\n", " 1 0 0]\n", " win2 = [1 1 2\n", " 1 2 0\n", " 2 0 0]\n", " nowin = [1 1 2\n", " 2 2 1\n", " 1 2 1]\n", " breaks = [1 2 1\n", " 2 1 2]\n", " # write tests here\n", "end" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Using the Primes module\n", "While the previous modules may help you with general Julia development, the `Primes` module will specifically be useful for solving Euler problems. Many Euler problems ask you to calculate values from primes and you may want to check whether certain problems are primes.\n", "\n", "To generate primes, we can use the `primes(hi)` function:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "using Primes\n", "\n", "# generating primes" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If we want to check whether a number is prime, we can use the `isprime(num)` method. We can also factor numbers using `factor(num)`, which returns a `Factorization` type that functions a little like a dictionary." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# checking isprime\n", "\n", "# checking factor" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Sometimes it's useful to know the [_totient_](https://en.wikipedia.org/wiki/Totient) of a number, $\\phi(n)$, which is the number of positve integers less than $n$ that are [relatively prime](https://en.wikipedia.org/wiki/Coprime_integers) to $n$. `Primes` can do that for us." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# passing factorization\n", "\n", "# calling totient directly" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Homework\n", "\n", "This week, we'll be giving you some homework based on the packages we taught you this week." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Project Euler Problem 22\n", "\n", "> https://projecteuler.net/problem=22\n", "\n", "> Using [names.txt](https://projecteuler.net/project/resources/p022_names.txt) (right click and 'Save Link/Target As...'), a 46K text file containing over five-thousand first names, begin by sorting it into alphabetical order. Then working out the alphabetical value for each name, multiply this value by its alphabetical position in the list to obtain a name score.\n", ">\n", "> For example, when the list is sorted into alphabetical order, COLIN, which is worth 3 + 15 + 12 + 9 + 14 = 53, is the 938th name in the list. So, COLIN would obtain a score of 938 Γ 53 = 49714.\n", ">\n", "> What is the total of all the name scores in the file?\n", "\n", "_Hint: make use of `read()`, `strip()`, and `map()` or the broadcast operator_" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Project Euler Problem 42\n", "> https://projecteuler.net/problem=42\n", "\n", "
\n", "" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Project Euler Problem 10\n", "\n", "> https://projecteuler.net/problem=10\n", "\n", "> The sum of the primes below 10 is 2 + 3 + 5 + 7 = 17.\n", ">\n", "> Find the sum of all the primes below two million.\n", "\n", "_With the `Primes` package, this one is pretty easy. For extra credit, build your own prime generator. [Here is one good method](https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes)._" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Practicing satisfying tests\n", "\n", "For this exercise, you're going to provided with a 2D minesweeper board (a 2D matrix) of any given dimensions filled with `true`s and `false`s, where `true`s are **mines** and `false`s are **empty space**. It's your job to generate a minesweeper board from this matrix, replacing the `true`s with the character `'X'` to signify mines, and replacing the `false`s with the number of _nearby mines_. A mine is _nearby_ to a space if it is contained in the $3\\times 3$ square around the space.\n", "\n", "Your goal is to pass the `@testset` beneath the function below. Once you have done so, add another couple tests of your choosing with gameboards of your choice." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "using Test\n", "\n", "function generateMineBoard(board::Array{Bool, 2})::Array{Any, 2}\n", " mineBoard = Array{Any, 2}(undef, size(board))\n", " # fill in mineBoard with your code here\n", "end\n", "\n", "@testset \"Minesweeper Tests\" begin\n", " X = 'X'\n", " input = [0 0 0 0 0 0\n", " 0 1 0 0 0 0\n", " 1 0 0 0 1 0\n", " 1 1 0 1 0 0]\n", " expected = [1 1 1 0 0 0\n", " 2 X 1 1 1 1\n", " X 4 3 2 X 1\n", " X X 2 X 2 1]\n", " @test generateMineBoard(convert(Array{Bool,2}, input)) == expected\n", " input2 = [0 0 0 0 0 0 0 0 1 0\n", " 0 0 0 1 0 1 0 0 0 0\n", " 0 0 0 0 1 0 0 0 0 0\n", " 1 0 0 0 0 0 0 0 0 0\n", " 0 0 0 0 0 0 0 0 0 0\n", " 0 0 0 0 1 0 0 0 1 0\n", " 0 0 1 0 1 0 0 0 0 0\n", " 0 0 0 0 0 0 0 0 0 0\n", " 0 0 0 0 0 1 0 0 0 0]\n", " expected2 = [0 0 1 1 2 1 1 1 X 1\n", " 0 0 1 X 3 X 1 1 1 1\n", " 1 1 1 2 X 2 1 0 0 0\n", " X 1 0 1 1 1 0 0 0 0\n", " 1 1 0 1 1 1 0 1 1 1\n", " 0 1 1 3 X 2 0 1 X 1\n", " 0 1 X 3 X 2 0 1 1 1\n", " 0 1 1 2 2 2 1 0 0 0\n", " 0 0 0 0 1 X 1 0 0 0]\n", " @test generateMineBoard(convert(Array{Bool, 2}, input2)) == expected2\n", " @test generateMineBoard(convert(Array{Bool, 2}, [0 0 0; 1 1 1; 0 0 0])) == [2 3 2; X X X; 2 3 2]\n", " @test generateMineBoard(convert(Array{Bool, 2}, [1 0; 0 0; 0 1])) == [X 1; 2 2; 1 X]\n", " @test generateMineBoard(ones(Bool, (5,5))) == fill('X', (5,5))\n", " @test generateMineBoard(zeros(Bool, (5,5))) == zeros(Bool, (5,5))\n", "end" ] } ], "metadata": { "kernelspec": { "display_name": "Julia 1.4.2", "language": "julia", "name": "julia-1.4" }, "language_info": { "file_extension": ".jl", "mimetype": "application/julia", "name": "julia", "version": "1.4.2" } }, "nbformat": 4, "nbformat_minor": 4 }The nth term of the sequence of triangle numbers is given by, tn = Β½n(n+1); so the first ten triangle numbers are:
\n", "1, 3, 6, 10, 15, 21, 28, 36, 45, 55, ...
\n", "By converting each letter in a word to a number corresponding to its alphabetical position and adding these values we form a word value. For example, the word value for SKY is 19 + 11 + 25 = 55 = t10. If the word value is a triangle number then we shall call the word a triangle word.
\n", "Using words.txt (right click and 'Save Link/Target As...'), a 16K text file containing nearly two-thousand common English words, how many are triangle words?
\n", "