Skip to content

Instantly share code, notes, and snippets.

@swt30
Last active January 21, 2016 10:59
Show Gist options
  • Save swt30/00dc456b5bc6b28fc65c to your computer and use it in GitHub Desktop.
Save swt30/00dc456b5bc6b28fc65c to your computer and use it in GitHub Desktop.
In-progress Julia version of Peter Norvig's "Refactoring a Crossword Game Program" notebook
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Crossword Game Program\n",
"\n",
"Based on [this excellent notebook](http://nbviewer.ipython.org/url/norvig.com/ipython/Scrabble.ipynb) by Peter Norvig.\n",
"\n",
"## Dictionary and Words\n",
"\n",
"The dictionary is a list of words, and each word is an uppercase string of letters, like 'WORD'. We use the ENABLE dictionary, downloading and caching it:"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"; [ -e enable1.txt ] || curl -O http://norvig.com/ngrams/enable1.txt"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The shell-mode symbol `;` at the start of the line allows us to enter shell commands directly. It can be used in the REPL or notebook. In a script we'd have to construct a `Cmd` object or use Julia equivalents like the `isfile` and `download` functions.\n",
"\n",
"Next we define what a \"word\" is by making a function that takes a string, removes whitespace and newlines, and makes it uppercase."
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"word (generic function with 1 method)"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"\"Make a word (an uppercase string of letters)\"\n",
"word(w) = uppercase(strip(w))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Throughout the rest of the notebook, most cells where things are defined are finished with a semicolon. This suppresses display to the notebook—otherwise we will see a lot of noise in the form of `(generic function with N methods)`... \n",
"\n",
"Next we construct the dictionary. Here we use the `readdlm` function to read a newline-delimited file. We need to specify that the lines are read as strings, otherwise words like FALSE will behave a little unexpectedly! Then we use `map` on it to convert all the lines into words. "
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"\"The ENABLE dictionary; a list of legal words\"\n",
"const DICTIONARY = map(word, readdlm(\"enable1.txt\", '\\n', ASCIIString))\n",
"\n",
"\"Check if `word` is a legal word in the dictionary.\"\n",
"isword(word) = uppercase(word) in DICTIONARY;"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Above, I have provided docstrings—a description of what a function does or what a variable represents—by writing a string directly above the definition. Julia allows you to write Markdown in docstrings, and retrieve them at the REPL or notebook by typing `?thingname`.\n",
"\n",
"Let's check that our dictionary looks good."
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"172820"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"length(DICTIONARY)"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"10-element Array{ASCIIString,1}:\n",
" \"AA\" \n",
" \"AAH\" \n",
" \"AAHED\" \n",
" \"AAHING\" \n",
" \"AAHS\" \n",
" \"AAL\" \n",
" \"AALII\" \n",
" \"AALIIS\" \n",
" \"AALS\" \n",
" \"AARDVARK\""
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"DICTIONARY[1:10]"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"true"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"\"WORD\" in DICTIONARY"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"true"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"isword(\"Word\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Tiles, Blanks, and Racks\n",
"\n",
"Each tile has a single character on it, like 'W'. A rack is represented as a string of tiles, usually of length 7, such as \"EELRTTS\".\n",
"\n",
"Treating the blank is a little harder. From the notebook:\n",
"\n",
"> The blank tile causes some complications. We'll represent a blank in a player's rack as the underscore character, '`_`'. But once the blank is played on the board, it must be used as if it was a specific letter. However, it doesn't score the points of the letter. I chose to use the lowercase version of the letter to represent this. That way, we know what letter the blank is standing for, and we can distingush between scoring and non-scoring tiles. For example, \"EELRTT`_`\" is a rack that contains a blank; and \"LETTERs\" is a word played on the board that uses the blank to stand for the letter S.\n",
"\n",
"We define three helper functions:\n",
"\n",
"- `letters` gives all the distinct letters in a rack\n",
"- `remove` removes letters from a rack (i.e. after they have been played)\n",
"- `expandblanks` removes all blank `_` tiles from a string and adds the lowercase alphabet (that is, the letters that a blank can be converted to)."
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"\"The character used to mark a blank tile\"\n",
"const BLANK = '_';"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Julia distinguishes between characters, marked with single quotes, and strings, marked with double quotes."
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"\"The alphabet, in lowercase\"\n",
"const ALPHABET = \"abcdefghijklmnopqrstuvwxyz\"\n",
"\n",
"\"Replace a blank tile in a rack with the options available (i.e. every letter in the alphabet)\"\n",
"expandblanks(str) = replace(str, BLANK, \"\") * ALPHABET\n",
"\n",
"\"Get all the distinct letters in a `rack`, including options from any blank tiles\"\n",
"function letters(rack)\n",
" if BLANK in rack\n",
" rack |> unique |> join |> expandblanks\n",
" else\n",
" rack |> unique |> join\n",
" end\n",
"end\n",
"\n",
"\"Return a copy of a `rack` with the given `tiles` removed\"\n",
"function remove(tiles, rack)\n",
" for tile in tiles\n",
" islower(tile) && (tile = BLANK)\n",
" rack = replace(rack, tile, \"\", 1)\n",
" end\n",
" \n",
" rack\n",
"end; "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Above I've used the `|>` pipe operator, which lets us write function applications in a left-to-right form. This makes it clearer what sequence of operations are being performed on the rack, rather than writing `expandblanks(join(unique(rack)))`."
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"true"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"isword(\"LETTERs\")"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"\"LETRS\""
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"letters(\"LETTERS\")"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"\"LETRabcdefghijklmnopqrstuvwxyz\""
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"letters(\"LETTER_\")"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"\"LTER\""
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"remove(\"SET\", \"LETTERS\")"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"\"LE\""
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"remove(\"TREaT\", \"LETTER_\") "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## The Board, Squares, Directions, and Bonus Squares\n",
"\n",
"Here we take advantage of Julia's type system to handle the board and tiles. We diverge from the Python version here by making the board into a two-dimensional matrix instead of a 1D list. We use the following setup:\n",
"\n",
"We make a `Tile` type. It is just a wrapper for a single character."
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"\"A letter tile\"\n",
"type Tile\n",
" letter::Char\n",
"end"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Then we make an abstract Square type."
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"abstract Square"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We now need to represent each square's properties. We make two separate concrete types. \n",
"\n",
"The first square type represents \"no-go\" squares. It is an approach which removes the need for bounds checking at the edge of the board, provided we surround the board with these squares. It will also provide the flexibility to define boards of a funny shape, or with holes in the middle, if we want. This type has no fields."
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"\"A no-go square - for example, off the edge of the board\"\n",
"type EdgeSquare <: Square; end"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The bonus type of each standard square is represented by an *enum*, which is constructed with the `@enum` macro: a `Bonus` can be any of SL, DL, TL, DW, TW, or ★. Julia's Unicode functionality means we can work directly with symbols like ★ (\\bigstar). "
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"@enum Bonus SL DL TL DW TW ★"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Enums are useful for representing choices from a limited list like this.\n",
"\n",
"The second square type then represents standard squares on the board. It stores information about any tile on it, plus the bonus type of the square."
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"\"A square on the board\"\n",
"type BoardSquare <: Square\n",
" tile::Nullable{Tile}\n",
" bonus::Bonus\n",
"end"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Here we have used `Nullable{Tile}` as the type for the `tile` field. This indicates that a `BoardSquare` may hold either `Tile` or `nothing`.\n",
"\n",
"We could also have made a separate subtype for each bonus square if we wanted. When dealing with just a few categories like this, making more subtypes is easy, and it lets us use the dispatch system to do the work of handling different items. But this can easily go too far, so we chose to keep the number of types low, making a distinction only between \"real\" and \"edge\" squares. (Think about the design of your program: is the bonus so fundamental to the character of the square that you want to have a bunch of different types called DoubleLetterSquare, StarSquare, and so on? Or is it enough to treat it as an additional property and store it in a field, similar to the way the square keeps track of whether a tile is on it?)\n",
"\n",
"We make a dictionary mapping some ASCII symbols to the type of square they represent. This will let us input the board in a simplified form."
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"\"A mapping from ASCII characters to square types\"\n",
"ASCIISQUARES = Dict(zip(\".:;-=*#\", [SL, DL, TL, DW, TW, ★, EdgeSquare]))\n",
"\n",
"# the reverse mapping is also useful\n",
"\"A mapping from square types to ASCII characters\"\n",
"SQUARESASCII = Dict(zip(values(ASCIISQUARES), keys(ASCIISQUARES)));"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Finally, we can treat the `Board` as a a 2D array of `Square`s. This lets us use a simple typealias to get all the functionality of a 2D array."
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"typealias Board Matrix{Square};"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In Julian style, we can now define some constructors to make `Square`s and `Board`s using multiple dispatch. By default, we assume that Squares are uncovered, on the board, and have no bonus (single letter score):"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"# basic blank square\n",
"Square() = BoardSquare(nothing, SL);"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"But we also provide constructors for specifying a square on the board's edge or one covered with a tile."
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"# blank square specified with a bonus designation\n",
"Square(b::Bonus) = BoardSquare(nothing, b)\n",
"\n",
"# edge square\n",
"Square(::Type{EdgeSquare}) = EdgeSquare()\n",
"\n",
"# square specified with an ASCII character short code\n",
"Square(bonus::Char) = Square(ASCIISQUARES[bonus])\n",
"\n",
"# a square on the board covered with a tile\n",
"Square(t::Tile, b::Bonus) = BoardSquare(t, b)\n",
"Square(t::Char, b::Bonus) = BoardSquare(Tile(t), b);"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"BoardSquare(Nullable{Tile}(),SL::Bonus)"
]
},
"execution_count": 24,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# a square with nothing on it\n",
"Square()"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"EdgeSquare()"
]
},
"execution_count": 25,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# an edge square\n",
"Square('#')"
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"BoardSquare(Nullable{Tile}(),TW::Bonus)"
]
},
"execution_count": 26,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# a triple word square\n",
"Square('=')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The text display of these squares is not particularly compact or nice. Let's add `show` methods to handle this. In particular, we'll define `showcompact` to print a single ASCII character, which will make arrays of these squares look much better. Then we'll get `show` to print a slightly expanded version."
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"\"Get a single character representation of a square\"\n",
"singlechar(::EdgeSquare) = '#'\n",
"singlechar(t::Tile) = t.letter\n",
"\n",
"function singlechar(s::Square)\n",
" if isnull(s.tile)\n",
" return SQUARESASCII[s.bonus]\n",
" else\n",
" return singlechar(get(s.tile))\n",
" # the \"get\" here unwraps the Nullable\n",
" end\n",
"end\n",
"\n",
"import Base: showcompact, show\n",
"\n",
"showcompact(io::IO, s::Square) = print(io, singlechar(s))\n",
"\n",
"function show(io::IO, s::Square)\n",
" print(io, \"Square('\")\n",
" showcompact(io, s)\n",
" print(io, \"')\")\n",
"end;"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now when we print a square, it should show in a more compact form (using its ASCII symbol)"
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"Square('.')"
]
},
"execution_count": 28,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Square()"
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"Square('#')"
]
},
"execution_count": 29,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"EdgeSquare()"
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"Square('=')"
]
},
"execution_count": 30,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Square(TW)"
]
},
{
"cell_type": "code",
"execution_count": 31,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"Square('B')"
]
},
"execution_count": 31,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Square('B', DW) # the double word is masked by the tile"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Next, let's get the board up and running. A Board can already be constructed as an array of squares:"
]
},
{
"cell_type": "code",
"execution_count": 32,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"4x4 Array{Square,2}:\n",
" # # # #\n",
" # . . #\n",
" # . . #\n",
" # # # #"
]
},
"execution_count": 32,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"[EdgeSquare() EdgeSquare() EdgeSquare() EdgeSquare();\n",
" EdgeSquare() Square() Square() EdgeSquare();\n",
" EdgeSquare() Square() Square() EdgeSquare();\n",
" EdgeSquare() EdgeSquare() EdgeSquare() EdgeSquare()]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"But that is cumbersome. We follow the nice example of the Python approach by allowing the `Board` to be constructed from a string too:"
]
},
{
"cell_type": "code",
"execution_count": 33,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"wwflayout = \"\"\"\n",
"# # # # # # # # # # # # # # # # #\n",
"# . . . = . . ; . ; . . = . . . #\n",
"# . . : . . - . . . - . . : . . #\n",
"# . : . . : . . . . . : . . : . #\n",
"# = . . ; . . . - . . . ; . . = #\n",
"# . . : . . . : . : . . . : . . #\n",
"# . - . . . ; . . . ; . . . - . #\n",
"# ; . . . : . . . . . : . . . ; #\n",
"# . . . - . . . * . . . - . . . #\n",
"# ; . . . : . . . . . : . . . ; #\n",
"# . - . . . ; . . . ; . . . - . #\n",
"# . . : . . . : . : . . . : . . #\n",
"# = . . ; . . . - . . . ; . . = #\n",
"# . : . . : . . . . . : . . : . #\n",
"# . . : . . - . . . - . . : . . #\n",
"# . . . = . . ; . ; . . = . . . #\n",
"# # # # # # # # # # # # # # # # #\n",
"\"\"\"\n",
"\n",
"\"Get the number of rows in a board layout\"\n",
"nrows(layout) = count(x -> x=='\\n', layout)\n",
"\n",
"\"Get the total number of squares, including edges, in a board layout\"\n",
"nsquares(layout) = length(split(layout))\n",
"\n",
"\"Get the number of columns in a board layout\"\n",
"ncols(layout) = div(nsquares(layout), nrows(layout));"
]
},
{
"cell_type": "code",
"execution_count": 34,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"17"
]
},
"execution_count": 34,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"ncols(wwflayout)"
]
},
{
"cell_type": "code",
"execution_count": 35,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"17"
]
},
"execution_count": 35,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"nrows(wwflayout)"
]
},
{
"cell_type": "code",
"execution_count": 36,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"17x17 Array{Square,2}:\n",
" # # # # # # # # # # # # # # # # #\n",
" # . . . = . . ; . ; . . = . . . #\n",
" # . . : . . - . . . - . . : . . #\n",
" # . : . . : . . . . . : . . : . #\n",
" # = . . ; . . . - . . . ; . . = #\n",
" # . . : . . . : . : . . . : . . #\n",
" # . - . . . ; . . . ; . . . - . #\n",
" # ; . . . : . . . . . : . . . ; #\n",
" # . . . - . . . * . . . - . . . #\n",
" # ; . . . : . . . . . : . . . ; #\n",
" # . - . . . ; . . . ; . . . - . #\n",
" # . . : . . . : . : . . . : . . #\n",
" # = . . ; . . . - . . . ; . . = #\n",
" # . : . . : . . . . . : . . : . #\n",
" # . . : . . - . . . - . . : . . #\n",
" # . . . = . . ; . ; . . = . . . #\n",
" # # # # # # # # # # # # # # # # #"
]
},
"execution_count": 36,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"function Board(layout::ASCIIString)\n",
" # discarding spaces and newlines from the string\n",
" boardchars = filter(c -> c ∉ \"\\n \", layout) # that's the not-in symbol, \\notin \n",
" # split into single characters and turn those characters into squares\n",
" board_1d = map(Square, collect(boardchars))\n",
" \n",
" # shape into a 2D array\n",
" size = (ncols(layout), nrows(layout))\n",
" reshape(board_1d, size) \n",
"end\n",
"\n",
"WWF = Board(wwflayout)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We haven't included any treatment for malformed input here - something to keep in mind if we wanted to polish this up more.\n",
"\n",
"## Displaying the Board in HTML\n",
"\n",
"From the notebook:\n",
"\n",
"> I want to diaplay the board in HTML, as a table with different background colors for the bonus squares; and gold-colored letter tiles. I also want to display the point values for each letter on the tiles.\n",
"\n",
"We will use dictionaries to map between squares and colors/text size, as well as between letters and point values.\n",
"\n",
"First we make single squares display in HTML:"
]
},
{
"cell_type": "code",
"execution_count": 37,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"\"Mapping between square type and decoration\"\n",
"SQUARECOLORS = Dict(\n",
" # color size text\n",
" DL=>(\"lightblue\", 66, \"DL\"),\n",
" TL=>(\"lightgreen\", 66, \"TL\"),\n",
" DW=>(\"lightcoral\", 66, \"DW\"),\n",
" TW=>(\"orange\", 66, \"TW\"),\n",
" SL=>(\"whitesmoke\", 66, \"\"),\n",
" ★ =>(\"violet\", 100, \"★\"))\n",
"\n",
"\"Make a string containing a HTML table cell\"\n",
"function htmlcell(color, size, text)\n",
" style = \"background-color:$color; font-size:$size%; width:25px; height:25px; text-align:center; padding:0px\"\n",
" \n",
" \"<td style='$style'>$text</div>\"\n",
"end\n",
"\n",
"function htmlcell(sq::Square)\n",
" if isnull(sq.tile)\n",
" color, size, text = SQUARECOLORS[sq.bonus]\n",
" htmlcell(color, size, text)\n",
" else\n",
" htmlcell(get(sq.tile))\n",
" end\n",
"end;"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In order to change how a square displays in HTML (and therefore in the notebook), we just need to provide an additional method for the `writemime` function."
]
},
{
"cell_type": "code",
"execution_count": 38,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<table><td style='background-color:lightcoral; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>DW</div></table"
],
"text/plain": [
"Square('-')"
]
},
"execution_count": 38,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import Base.writemime\n",
"\n",
"function writemime(io::IO, ::MIME\"text/html\", sq::Square)\n",
" # when writing a square by itself, we need to make it a standalone table\n",
" write(io, \"<table>\")\n",
" write(io, htmlcell(sq))\n",
" write(io, \"</table\")\n",
"end\n",
"\n",
"Square(DW)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"But we haven't yet provided this method for the `Tile` type."
]
},
{
"cell_type": "code",
"execution_count": 39,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"Tile('Z')"
]
},
"execution_count": 39,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Tile('Z') # it will still be plain text"
]
},
{
"cell_type": "code",
"execution_count": 40,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<table><td style='background-color:gold; font-size:120%; width:25px; height:25px; text-align:center; padding:0px'><b>Z</b><sup style=\"font-size: 60%\">10</sup></div></table>"
],
"text/plain": [
"Tile('Z')"
]
},
"execution_count": 40,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"\"Mapping between letter and point value\"\n",
"POINTS = let\n",
" pointvals = [1, 3, 3, 2, 1, 4, 2, 4, 1, 8, 5, 1, 3, \n",
" 1, 1, 3, 10, 1, 1, 1, 1, 4, 4, 8, 4, 10]\n",
" \n",
" Dict(zip(uppercase(ALPHABET), pointvals))\n",
"end\n",
"\n",
"function htmlcell(t::Tile)\n",
" color = \"gold\"\n",
" size = 120\n",
" letter = t.letter\n",
" points = POINTS[letter]\n",
" text = \"<b>$letter</b><sup style=\\\"font-size: 60%\\\">$points</sup>\"\n",
" htmlcell(color, size, text)\n",
"end\n",
"\n",
"function writemime(io::IO, ::MIME\"text/html\", t::Tile)\n",
" write(io, \"<table>\")\n",
" write(io, htmlcell(t))\n",
" write(io, \"</table>\")\n",
"end\n",
"\n",
"Tile('Z')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now it's easy to display the whole board. We do this by first constructing a HTML template for the table that looks like this:\n",
"\n",
" <table> <tr> X X X\n",
" <tr> X X X\n",
" <tr> X X X\n",
" </table> "
]
},
{
"cell_type": "code",
"execution_count": 41,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"height(b::Board) = size(b)[1] - 2\n",
"width(b::Board) = size(b)[2] - 2\n",
"trimedges(board) = board[2:end-1, 2:end-1]\n",
"\n",
"\"Give a template HTML table where the position of each <td>, to be filled later, is marked with an X\"\n",
"function tablerows(nrows, ncols)\n",
" row = \"<tr>\" * repeat(\"X\", ncols)\n",
" table = \"<table>\" * repeat(row, nrows) * \"</table>\"\n",
"end;"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Then making the full HTML table just requires looping through the string and replacing each X with a table cell. There are probably nicer ways to do this sort of templating, but it will do for now."
]
},
{
"cell_type": "code",
"execution_count": 42,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<table><tr><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:lightgreen; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>TL</div><tr><td style='background-color:lightcoral; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>DW</div><td style='background-color:lightblue; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>DL</div></table>"
],
"text/plain": [
"4x4 Array{Square,2}:\n",
" # # # #\n",
" # . - #\n",
" # ; : #\n",
" # # # #"
]
},
"execution_count": 42,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"\"Get the HTML representation of a board\"\n",
"function html(board::Board)\n",
" squares = trimedges(board)\n",
" table = tablerows(height(board), width(board))\n",
" for sq in squares\n",
" table = replace(table, 'X', htmlcell(sq), 1)\n",
" end\n",
" \n",
" table\n",
"end\n",
"\n",
"Base.writemime(io, ::MIME\"text/html\", b::Board) = write(io, html(b))\n",
"\n",
"Board(\"\"\"\n",
"# # # #\n",
"# . ; #\n",
"# - : #\n",
"# # # #\n",
"\"\"\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's see what the full board looks like!"
]
},
{
"cell_type": "code",
"execution_count": 43,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<table><tr><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:orange; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>TW</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:lightgreen; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>TL</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:lightgreen; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>TL</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:orange; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>TW</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><tr><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:lightblue; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>DL</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:lightcoral; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>DW</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:lightcoral; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>DW</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:lightblue; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>DL</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><tr><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:lightblue; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>DL</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:lightblue; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>DL</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:lightblue; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>DL</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:lightblue; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>DL</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><tr><td style='background-color:orange; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>TW</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:lightgreen; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>TL</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:lightcoral; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>DW</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:lightgreen; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>TL</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:orange; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>TW</div><tr><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:lightblue; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>DL</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:lightblue; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>DL</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:lightblue; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>DL</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:lightblue; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>DL</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><tr><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:lightcoral; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>DW</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:lightgreen; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>TL</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:lightgreen; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>TL</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:lightcoral; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>DW</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><tr><td style='background-color:lightgreen; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>TL</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:lightblue; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>DL</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:lightblue; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>DL</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:lightgreen; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>TL</div><tr><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:lightcoral; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>DW</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:violet; font-size:100%; width:25px; height:25px; text-align:center; padding:0px'>★</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:lightcoral; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>DW</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><tr><td style='background-color:lightgreen; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>TL</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:lightblue; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>DL</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:lightblue; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>DL</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:lightgreen; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>TL</div><tr><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:lightcoral; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>DW</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:lightgreen; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>TL</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:lightgreen; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>TL</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:lightcoral; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>DW</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><tr><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:lightblue; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>DL</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:lightblue; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>DL</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:lightblue; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>DL</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:lightblue; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>DL</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><tr><td style='background-color:orange; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>TW</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:lightgreen; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>TL</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:lightcoral; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>DW</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:lightgreen; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>TL</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:orange; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>TW</div><tr><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:lightblue; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>DL</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:lightblue; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>DL</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:lightblue; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>DL</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:lightblue; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>DL</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><tr><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:lightblue; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>DL</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:lightcoral; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>DW</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:lightcoral; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>DW</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:lightblue; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>DL</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><tr><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:orange; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>TW</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:lightgreen; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>TL</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:lightgreen; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>TL</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:orange; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'>TW</div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div><td style='background-color:whitesmoke; font-size:66%; width:25px; height:25px; text-align:center; padding:0px'></div></table>"
],
"text/plain": [
"17x17 Array{Square,2}:\n",
" # # # # # # # # # # # # # # # # #\n",
" # . . . = . . ; . ; . . = . . . #\n",
" # . . : . . - . . . - . . : . . #\n",
" # . : . . : . . . . . : . . : . #\n",
" # = . . ; . . . - . . . ; . . = #\n",
" # . . : . . . : . : . . . : . . #\n",
" # . - . . . ; . . . ; . . . - . #\n",
" # ; . . . : . . . . . : . . . ; #\n",
" # . . . - . . . * . . . - . . . #\n",
" # ; . . . : . . . . . : . . . ; #\n",
" # . - . . . ; . . . ; . . . - . #\n",
" # . . : . . . : . : . . . : . . #\n",
" # = . . ; . . . - . . . ; . . = #\n",
" # . : . . : . . . . . : . . : . #\n",
" # . . : . . - . . . - . . : . . #\n",
" # . . . = . . ; . ; . . = . . . #\n",
" # # # # # # # # # # # # # # # # #"
]
},
"execution_count": 43,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"WWF"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Oh boy that's pretty!\n",
"\n",
"## Plays\n",
"\n",
"> A `Play` describes the placement of tiles on the board. \n",
"\n",
"We implement `Play` as an type with three components:\n",
"\n",
"- start: the coordinates of the square that holds the first letter in the word.\n",
"- dir: the direction of play; an enum\n",
"- letters: the letters of the word, in order, as a string. Blanks are lowercase. Some letters are from the rack; some may have been on the board."
]
},
{
"cell_type": "code",
"execution_count": 44,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"@enum PlayDirection ACROSS DOWN\n",
"\n",
"type Play\n",
" start::NTuple{2, Int}\n",
" dir::PlayDirection\n",
" letters::ASCIIString\n",
"end"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Julia 0.4.3",
"language": "julia",
"name": "julia-0.4"
},
"language_info": {
"file_extension": ".jl",
"mimetype": "application/julia",
"name": "julia",
"version": "0.4.3"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment