Starbeamrainbowlabs

Stardust
Blog


Archive


Mailing List Articles Atom Feed Comments Atom Feed Twitter Reddit Facebook

Tag Cloud

3d 3d printing account algorithms android announcement architecture archives arduino artificial intelligence artix assembly async audio automation backups bash batch blog bookmarklet booting bug hunting c sharp c++ challenge chrome os code codepen coding conundrums coding conundrums evolved command line compilers compiling compression css dailyprogrammer data analysis debugging demystification distributed computing documentation downtime electronics email embedded systems encryption es6 features ethics event experiment external first impressions future game github github gist gitlab graphics hardware hardware meetup holiday holidays html html5 html5 canvas infrastructure interfaces internet interoperability io.js jabber jam javascript js bin labs learning library linux lora low level lua maintenance manjaro network networking nibriboard node.js operating systems own your code performance phd photos php pixelbot portable privacy problem solving programming problems project projects prolog protocol protocols pseudo 3d python reddit redis reference releases resource review rust searching secrets security series list server software sorting source code control statistics storage svg talks technical terminal textures thoughts three thing game three.js tool tutorial twitter ubuntu university update updates upgrade version control virtual reality virtualisation visual web website windows windows 10 xmpp xslt

Converting multiline text to an image in PHP

This post is late because I lost the post I had written when I tried to save it - I need to find a new markdown editor. Do let me know if you have any suggestions!

I was working on Pepperminty Wiki earlier, and as I was working on external diagram renderer support (coming soon! It's really cool) I needed to upgrade my errorimage() function to support multi-line text. Pepperminty Wiki's key feature is that it's portable and builds (with a custom build system) to a single file of PHP that's plug-and-play, so no nice easy libraries here!

Instead, said function uses GD to convert text to images. This is kind of useful when you want to send back an error, but you also want to send an image because otherwise the user won't see it as they've used an <img src="" /> tag, which doesn't support displaying text, obviously.

To this end, I found myself wanting to add multi-line text support. This was quite an interesting task, because as errorimage() uses GD and Pepperminty Wiki needs to be portable, I can't use imagettftext() and use a nice font. Instead, it uses imagestring(), which draws things in a monospace font. This actually makes the whole proceeding much easier - especially since imagefontwidth() and imagefontheight() give us the width and height of a character respectively.

Here's what the function looked like before:

/**
 * Creates an images containing the specified text.
 * Useful for sending errors back to the client.
 * @package feature-upload
 * @param   string  $text           The text to include in the image.
 * @param   int     $target_size    The target width to aim for when creating
 *                                  the image.
 * @return  resource                The handle to the generated GD image.
 */
function errorimage($text, $target_size = null)
{
    $width = 640;
    $height = 480;

    if(!empty($target_size))
    {
        $width = $target_size;
        $height = $target_size * (2 / 3);
    }

    $image = imagecreatetruecolor($width, $height);
    imagefill($image, 0, 0, imagecolorallocate($image, 238, 232, 242)); // Set the background to #eee8f2
    $fontwidth = imagefontwidth(3);
    imagestring($image, 3,
        ($width / 2) - (($fontwidth * mb_strlen($text)) / 2),
        ($height / 2) - (imagefontheight(3) / 2),
        $text,
        imagecolorallocate($image, 17, 17, 17) // #111111
    );

    return $image;
}

...it's based on a Stack Overflow answer that I can no longer locate. It takes in a string of text, and draws an image with the specified size. This had to change too - since the text might not fit in the image. The awkward thing here is that I needed to maintain the existing support for the $target_size variable, making the code a bit messier than it needed to be.

To start here, let's define a few extra variables to hold some settings:

$width = 0;
$height = 0;
$border_size = 10; // in px, if $target_size isn't null has no effect
$line_spacing = 2; // in px
$font_size = 5; // 1 - 5

Looking better already! Variables like these will help us tune it later (I'm picky). The font size in PHP is a value from 1 to 5, with higher values corresponding to larger font sizes. The $border_size is the number of pixels around the text that we want to add as padding when we're in auto-sizing mode to make it look neater. The $line_spacing is the number of extra pixels of space we should add between lines to make the text look better.

So, about that image size. We'll need the size of a character for that:

$font_width = imagefontwidth($font_size);   // in px
$font_height = imagefontheight($font_size); // in px

....and we'll need to split the input text into a list of lines too:

$text_lines = array_map("trim", explode("\n", $text));

We use an array_map() call here to ensure we chop the whitespace of the end, because strange whitespace characters lying around will result in odd characters appearing in the output image. If the target size is set, then calculating the actual size of the image is easy:

if(!empty($target_size)) {
    $width = $target_size;
    $height = $target_size * (2 / 3);
}

If not, then we'll have to do some fancier footwork to count the maximum number of characters on a line to find the width of the image, and the number of lines we have for the image height:

else {
    $height = count($text_lines) * $font_height + 
        (count($text_lines) - 1) * $line_spacing +
        $border_size * 2;
    foreach($text_lines as $line)
        $width = max($width, $font_width * mb_strlen($line));
    $width += $border_size * 2;
}

Here we also don't forget about the line spacing either - which to get the number of spaces between the lines, we need to take the number of lines minus one. We also add the border as an offset value to the width and height too - multiplied by 2 because there's a border on both sides of the text.

Next, we need to create an image to draw the text to. This is largely the same as before:

$image = imagecreatetruecolor($width, $height);
imagefill($image, 0, 0, imagecolorallocate($image, 250, 249, 251)); // Set the background to #faf8fb

Now, we're ready to draw the text itself. This needs to now be done with a loop, because we've got multiple lines of text to draw - and imagestring() doesn't support that as we've discussed above. We also need to keep track of the index of the loop, so a temporary value is required:

$i = 0;
foreach($text_lines as $line) {
    // ....

    $i++;
}

With the loop in place, we can make the call to imagestring():

imagestring($image, $font_size,
    ($width / 2) - (($font_width * mb_strlen($line)) / 2),
    $border_size + $i * ($font_height + $line_spacing),
    $line,
    imagecolorallocate($image, 68, 39, 113) // #442772
);

This looks full of maths, but it's really quite simple. Let's break it down. Lines #2 and #3 there are the $(x, y)$ of the top-left corner at which the text should be drawn. Let's look at them in turn.

The $x$ co-ordinate (($width / 2) - (($font_width * mb_strlen($line)) / 2)) centres the text on the row. Basically, we take the centre of the image $width / 2), and take away ½ of the text width - which we calculate by taking the number of characters on the line, multiplying it by the width of a single character, and dividing it by 2.

The $y$ co-ordinate ($border_size + $i * ($font_height + $line_spacing)) is slightly different, because we need to account for the border at the top of the image. We take the font height, add the line spacing, and multiply it by the index of the text line that we're drawing. Since values start from 0 here, this will have no effect for the first line of text that we process, and it'll be drawn at the top of the image. We add to this the border width, to avoid drawing it inside the border that we've allocated around the image.

Lastly, the imagecolorallocate() call there tells GD the colour that we want to draw the text in via RGB. I've added a comment there because my editor highlights certain colour formats with the actual colour they represent, which is cool.

All that's left here is to return the completed image:

return $image;

....then we can do something like this:

if(!empty($error)) {
    http_response_code(503);
    header("content-type: image/png");
    imagepng(errorimage("Error: Something went\nwrong!")); // Note: Don't ever send generic error messages like this one. It makes for a bad and frustrating user (and debugging) experience.
}

I'm including the completed upgrade to the function at the bottom of this blog post. Here's an example image that it can render:

Found this interesting? Done some refactoring of your own recently? Comment below!)


(Can't see the above? Try a direct link.)

RhinoReminds: An XMPP reminder bot for my convenience

A Black Rhino from WikiMedia Commons. (Above: A Picture of a Black Rhino. Source: WikiMedia Commons)

Many times when I write a program it's to solve a problem. With Pepperminty Wiki, it was that I needed a lightweight wiki engine - and MediaWiki was just too complex. With TeleConsole, it was that I wanted to debug a C♯ Program in an environment that had neither a debugger nor a console (I'm talking about you, Unity 3D).

Today, I'm releasing RhinoReminds, an XMPP bot that reminds you about things. As you might have guessed, this is the end product of a few different posts I've made on here recently:

You can talk to it like so:

Remind me to water the greenhouse tomorrow at 4:03pm
Show all reminders
Delete reminders 2, 3, 4, and 7
Remind me in 1 hour to check the oven

...and it'll respond accordingly. It figures out which action to take based on the first word of the sentence you send it, but after that it uses AI (specifically Microsoft.Recognizers.Text, which I posted about here) to work out what you how you want it to do it.

I'm still working out a few bugs (namely reconnecting automagically after the connection to the server is lost, and ensuring all the messages it sends in reply actually make sense), but it's at the point now where it's stable enough that I can release it to everyone who'd either like to use it for themselves, or is simply curious :-)

If you'd like to run an instance of the bot for yourself, I recommend heading over to my personal git server here:

https://git.starbeamrainbowlabs.com/sbrl/RhinoReminds

The readme file should contain everything you need to know to get started. If not, let me know by contacting me, or commenting here!

Unfortunately, I'm not able to offer a public instance of this bot at the moment, due to concerns about spam. However, patches to improve the bots resistance against spammers (perhaps a cooldown period or something or too many messages are sent? or a limit of 50 active reminders per account?) are welcome.

Found this interesting? Got a cool use for it? Want help setting it up yourself? Comment below!

C# & .NET Terminology Demystified: A Glossary

After my last glossary post on LoRa, I thought I'd write another one of C♯ and .NET, as (in typical Microsoft fashion it would seem), they're seems to be a lot of jargon floating around whose meaning is not always obvious.

If you're new to C♯ and the .NET ecosystems, I wouldn't recommend tackling all of this at once - especially the bottom ~3 definitions - with those in particular there's a lot to get your head around.

C♯

C♯ is an object-oriented programming language that was invented by Microsoft. It's cross-platform, and is usually written in an IDE (Integrated Development Environment), which has a deeper understanding of the code you write than a regular text editor. IDEs include Visual Studio (for Windows) and MonoDevelop (for everyone else).

Solution

A Solution (sometimes referred to as a Visual Studio Solution) is the top-level definition of a project, contained in a file ending in .sln. Each solution may contain one or more Project Files (not to be confused with the project you're working on itself), each of which gets compiled into a single binary. Each project may have its own dependencies too: whether they be a core standard library, another project, or a NuGet package.

Project

A project contains your code, and sits 1 level down from a solution file. Normally, a solution file will sit in the root directory of your repository, and the projects will each have their own sub-folders.

While each project has a single output file (be that a .dll class library or a standalone .exe executable), a project may have multiple dependencies - leading to many files in the build output folder.

The build process and dependency definitions for a project are defined in the .csproj file. This file is written in XML, and can be edited to perform advanced build steps, should you need to do something that the GUI of your IDE doesn't support. I've blogged about the structuring of this file before (see here, and also a bit more here), should you find yourself curious.

CIL

Known as Common Intermediate Language, CIL is the binary format that C♯ (also Visual Basic and F♯ code) code gets compiled into. From here, the .NET runtime (on Windows) or Mono (on macOS, Linux, etc.) can execute it to run the compiled project.

MSBuild

The build system for Solutions and Projects. It reads a .sln or .csproj (there are others for different languages, but I won't list them here) file and executes the defined build instructions.

.NET Framework

The .NET Framework is the standard library of C♯ it provides practically everything you'll need to perform most common tasks. It does not provide a framework for constructing GUIs and Graphical Interfaces. You can browse the API reference over at the official .NET API Browser.

WPF

The Windows Presentation Foundation is a Windows-only GUI framework. Powered by XAML (eXtensible Application Markup Language) definitions of what the GUI should look like, it provides everything you need to create a native-looking GUI on Windows.

It does not work on macOS and Linux. To create a cross-platform program that works on all 3 operating systems, you'll need to use an alternative GUI framework, such as XWT or Gtk# (also: Glade). A more complete list of cross-platform frameworks can be found here. It's worth noting that Windows Forms, although a tempting option, aren't as flexible as the other options listed here.

C♯ 7

The 7th version of the C♯ language specification. This includes the syntax of the language, but not the .NET Framework itself.

.NET Standard

A specification of the .NET Framework, but not the C♯ Language. As of the time of typing, the latest version is 2.0, although version 1.6 is commonly used too. The intention here is the improve cross-platform portability of .NET programs by defining a specification for a subset of the full .NET Framework standard library that all platforms will always be able to use. This includes Android and iOS through the use of Xamarin.

Note that all .NET Standard projects are class libraries. In order to create an executable, you'll have to add an additional Project to your Solution that references your .NET Standard class library.

ASP.NET

A web framework for .NET-based programming languages (in our case C♯). Allows you to write C♯ code to handle HTTP (and now WebSockets) requests in a similar manner to PHP, but different in that your code still needs compiling. Compiled code is then managed by a web server IIS web server (on Windows).

With the release of .NET Core, ASP.NET is now obsolete.

.NET Core

Coming in 2 versions so far (1.0 and 2.0), .NET Core is the replacement for ASP.NET (though this is not its exclusive purpose). As far as I understand it, .NET Core is a modular runtime that allows programs targeting it to run multiple platforms. Such programs can either be ASP.NET Core, or a Universal Windows Platform application for the Windows Store.

This question and answer appears to have the best explanation I've found so far. In particular, the displayed diagram is very helpful:

A diagram showing the structure of the .NET ecosystem, including .NET Core. See the links in the sources and further reading below for more information.

....along with the pair of official "Introducing" blog posts that I've included in the Sources and Further Reading section below.

Conclusion

We've looked at some of the confusing terminology in the .NET ecosystems, and examined each of them in turn. We started by defining and untangling the process by which your C♯ code is compiled and run, and then moved on to the different variants and specifications related to the .NET Framework and C♯.

As always, this is a starting point - not an ending point! I'd recommend doing some additional reading and experimentation to figure out all the details.

Found this helpful? Still confused? Spotted a mistake? Comment below!

Sources and Further Reading

Quest Get: Search large amounts of code!

A map  of the Linux Kernel source code.

(Above: A map of the Linux Kernel source code. Source: this post on medium.)

Recently I was working on a little project of mine (nope, not this for once! :P), and I needed a C♯ class I'd written a while ago. Being forgetful as I am, I had no idea which of my project I'd written it for. And so the quest began to find it! I did in the end, but it left me thinking whether there was a better way to search all my code quickly. This post is the culmination of everything I've discovered so far about the process of searching one's code.

Before I started, I already know about grep, which is built into almost every Linux system around. It's even available for Windows via the MSYS Tools. Unfortunately though, despite it's prevailance, it's not particularly good at searching large numbers of git repositories, as it keeps descending into the .git folder and displaying a whole load of useless results.

Something had to change. After asking reddit, I was introduced to OpenGrok. Written in Java, it indexes all of your code, and provides a web interface through which you can search it. Very nice. Unfortunately, I had trouble figuring out the logistics of actually getting it to run - and discovered that it takes multiple hours to set up correctly.

Moving on, I was re-introduced to ack, written in plain-old Perl, it apparently runs practically any system that Perl does - though it's not installed by default like grep is. Looking into it, I found it to be much like grep - only smarter. It ignores version control directories (like the .git folder ), and common package folders (like node_modules) by default, and even has a system by which results can be filtered by language (with support for hash-bangs too!). The results themselves are coloured by default - making it easy to skim through quickly. Coupled with the flexible configuration file system, ack makes for a wonderfully flexible way to search through large amounts of code quickly.

Though ack looks good, I still didn't have a way to search through all my code that scattered across multiple devices at once, so I kept looking. The next project I found (through alternative to actually) was Text Sherlock. It positions itself as an alternative to OpenGrok that's much simpler to configure.

True to its word, I managed to get a test instance set up running from my /tmp directory in 15 minutes - though it did take a while to index the code I had locally. It also took several seconds to consult its index when I entered a query. I suspect I could alleviate both of these issues by installing Xapian (an open-source high-performance search library), which it appears to have support for.

While the interface was cool, it didn't appear to allow me to tell it which directories not to index, so it ended trawling through all my .git directories - just like grep did. It also doesn't appear to multi-threaded - so it took much longer to index my code than it really needed to (I've got a solid-state drive and enough RAM for a few GBs of cache, so the indexing operation was CPU-bound, not I/O-bound).

In the end, I've rediscovered the awesome search tool ack, and taken a look at the current state of code search tools today. While I haven't yet found precisely what I'm looking for, I'm further forward than when I started.

Other honourable mentions include GNU Global (which apparently needs several GiBs per ~300MiB of source code for its generated static HTML web interface), insight.io (an IDE-like freemium cloud product that 'understands your code'), CodeQuery (only supports C, C++, Java, Python, Ruby, Javascript, and Go), and ripgrep (rust-based program, similar to ack and grep, feature comparison). The official ack website has a good page that contains more tools that are worth a look, too.

Got a cool way to search through all your code? Did this help you out? Comment below!

Organise your code snippets with GistBox

Gistbox logo

As I have been progressing with my degree, I have found myself with an increasingly large library of reusable code. While this is a good thing as it means that I don't have to write the same functionality twice, I have been discovering that it is rather difficult to find the code snippet I want to use in any reasonable length of time - probably due to the absence of a meaningful organisational system.

Recently I found GistBox whilst scouring the internet for a decent solution. It lets you tag and organise the code snippets that you have uploaded to Github Gist. Now instead of hunting through past projects to find a piece of code I want to reuse, I can instead (in theory) just open GistBox and search that instead, assuming that I have gotten around to uploading that snippet to Github as a gist.

GistBox does have it's flaws (like a terribly uncustomizable code editor that doesn't let you switch between space and tabs), but all in all it's a huge improvement over my previous (non-existent) system. Now all I have to do is to move all my snippets over to it so that they are all in one place (assuming that I can find them).

Programming 2 Coursework - PickupTheCrew

A screenshot PickupTheCrew I recently got an email from a university friend asking for my Programming 2 coursework. It gave me the idea that I should make a blog post about it, so here it is. For my Programming 2 coursework this seester I was asked to build a game to a specification called "Pickup The Crew". My implementation can be found below:

I am releasing this under the CC-BY-SA (Creative Commons Attribution Share-Alike) license. If this is not the correct license for this thing, please contact me (leave a message in the comments!) and I will change it.

You can find it here: PickUpTheCrew

To extract the above archive you will need 7-zip. Once extracted navigate to PickupTheCrew\PickupTheCrew\bin\Windows\Release and double click PickupTheCrew.exe.

If you have any problems, please comment below and I will try to help.

Probably the world's most advanced string splitting function

When I was setting up this website, I foolishly picked a custom log file format that is rather hard for computers to parse. Because of this I haven't found a server log analysis tool that is intelligent enough to parse my logs (if you know of one please let me know in the comments!).

Here is an example of a typical log file entry:

[19/May/2015:00:47:52 +0100] "starbeamrainbowlabs.com" HTTP/1.1 GET 200 162.243.87.220 0s :443 /blog/article.php article=posts/013-Terminal-Reference.html "https://starbeamrainbowlabs.com/blog/?offset=60" "Mozilla/5.0 (compatible; spbot/4.4.2; +http://OpenLinkProfiler.org/bot )"

It looks strange, doesn't it? Since I want to have some idea of how many people are visiting my site, I have finally gotten around to writing my own custom log parser. In order to do this, I needed a way to convert each line into an array of terms. None of the answers on stackoverflow seemed to cut it, so I wrote my own:

<?php
function explode_adv($openers, $closers, $togglers, $delimiters, $str)
{
    $chars = str_split($str);
    $parts = [];
    $nextpart = "";
    $toggle_states = array_fill_keys($togglers, false); // true = now inside, false = now outside
    $depth = 0;
    foreach($chars as $char)
    {
        if(in_array($char, $openers))
            $depth++;
        elseif(in_array($char, $closers))
            $depth--;
        elseif(in_array($char, $togglers))
        {
            if($toggle_states[$char])
                $depth--; // we are inside a toggle block, leave it and decrease the depth
            else
                // we are outside a toggle block, enter it and increase the depth
                $depth++;

            // invert the toggle block state
            $toggle_states[$char] = !$toggle_states[$char];
        }
        else
            $nextpart .= $char;

        if($depth < 0) $depth = 0;

        if(in_array($char, $delimiters) &&
           $depth == 0 &&
           !in_array($char, $closers))
        {
            $parts[] = substr($nextpart, 0, -1);
            $nextpart = "";
        }
    }
    if(strlen($nextpart) > 0)
        $parts[] = $nextpart;

    return $parts;
}
?>

I have also posted this on stackoverflow. This function of mine takes 5 parameters:

  1. An array of characters that open a block - e.g. [, (, etc.
  2. An array of characters that close a block - e.g. ], ), etc.
  3. An array of characters that toggle a block - e.g. ", ', etc.
  4. An array of characters that should cause a split into the next part.
  5. The string to work on.

This function probably will have flaws, but it works well enough for me.

You can also find this function on GitHub's Gist - as always suggestions and contributions are always welcome :)

C Sharp Performance Tests: Squaring Numbers

The semester 2 coursework has begun, and this time there is a choice of either make a game to a specification, or produce a business related application to a specification. I have chosen the game.

To start off, I started writing a few mathematical functions that I would need when ewriting the game itself. I quickly found that one of things you do rather a lot is squaring numbers. In C♯ I have found 2 ways to square a number so far: a*a and Math.Pow(a, 2), where a is a number.

Even though it probably doesn't matter about the speed at which we square numbers (there are much better optimisations to make), I decided to test it anyway. I wrote this program:

using System;
using System.Diagnostics;

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("This program tests the performance of squaring numbers.\n");
        Console.WriteLine("Iterations | a*a Time | Math.Pow(a, 2) Time");
        Console.WriteLine("-----------|----------|--------------------");

        int iterations = 100000;
        double number = 3092d;
        double result;

        while(true)
        {
            Stopwatch timera = Stopwatch.StartNew();

            for(int i = 0; i < iterations; i++)
            {
                result = number*number;
            }
            timera.Stop();

            Stopwatch timerb = Stopwatch.StartNew();
            for(int i = 0; i < iterations; i++)
            {
                result = Math.Pow(number, 2);
            }
            timerb.Stop();

            Console.WriteLine(" {0,9} | {1,8} | {2}", iterations, timera.ElapsedMilliseconds.ToString(), timerb.ElapsedMilliseconds.ToString());

            iterations += 100000;

            System.Threading.Thread.Sleep(500); // make sure that we don't crash the server
        }
    }
}

(pastebin, binary)

I didn't have a Windows Machine handy when writing this post, so the binary has been compiled with mono's dcms. Please leave a comment below if it doesn't work for you.

Everything is done with doubles to maek it a fair test because C♯'s Math.Pow method will only accept a double. The code sleeps for half a second between runs because I was writing this on the server that is serving the websitee, and I didn't want to crash it by accident :)

The results were rather shocking. The easiest way to display the results is in a graph:

A graph of the results.

A pastebin of the results can be found here.

As you can quite clearly see, Math.Pow() is horribly inefficient compared to just multiplying a number by itself. Next time I am squaring numbers, I won't be using Math.Pow again.

Coding Conundrums 2

Number two in a series of more than one. Definitely.

Welcome to my solutions to Rob Miles' Coding Conundrums 2. The problem descriptions can be found below, along with pastebin and 32 bit binary links (other binary type available upon request). If you need any help, please ask in the comments below.

2.1: Crazy Times Tables

Description

A teacher friend wants to be able to print out stupid times-tables for their kids at school. Perhaps they are not a maths teacher. I have no idea. Anyhoo, the program should request the number of the table (for examplethe3.7 times table) and then print out 1 to 12 timesthat value:

What times table do you want? 3.71

times 3.7 is 3.72 times 3.5 is 7.4..

and so on

The teacher tells you that the 0 times table and the 1 times table are too easy and the program should reject those, but any other value (including negative ones) is OK.

My Solution

This solution works ok, but you get a few inaccuracies with certain values. Changing float to double or decimal would probably solve those issues.

using System;

public class CrazyTables
{
    public static void Main(string[] args)
    {
        if(args.Length != 1)
        {
            Console.WriteLine("Use it like this: ");
            Console.WriteLine("    CrayTables.exe <float>");
            Console.WriteLine("\n<float>: The number to use when generating the times table.");
            return;
        }

        float number = float.Parse(args[0].Trim());

        if(number == 0 || number == 1)
        {
            Console.WriteLine("Invalid times table number.");
            return;
        }

        for(int i = 0; i < 12; i++)
        {
            Console.WriteLine("{0,2} times {1} is {2,2}", i + 1, number, (i + 1) * number);
        }
    }

    public static bool ValidateInput(float number)
    {
        if (number == 0 || number == 1)
            return false;
        else
            return true;
    }
}

(Pastebin, 32 bit binary)

2.2: Scrabble™ Scores

Description

Scrabble™ is a word game. Players take turns to make words out of letter tiles. Each tile has a particular value. Generally, the rarer the letter in words, the higher the value. The tiles have the following values:

  • (1 point)-A, E, I, O, U, L, N, S, T, R
  • (2 points)-D, G
  • (3 points)-B, C, M, P
  • (4points)-F, H, V, W, Y
  • (5 points)-K
  • (8 points)-J, X
  • (10 points)-Q, Z

I want a program that will tell me how much a given word is worth in Scrabble™. Turns out that Rob Miles is worth 12 points, I'd like to be able to find out if anyone else has a name worth more than mine.

My Solution

Another C♯ Dictionary here.

using System;
using System.Collections.Generic;

public class ScrabbleScorer
{
    public static void Main(string[] args)
    {
        if(args.Length != 1)
        {
            Console.WriteLine("Use it like this:");
            Console.WriteLine("    ScrabbleScorer.exe <word>");
            Console.WriteLine("\n<word>: The word to calculate the score for.");
            return;
        }

        Console.WriteLine("'{0}' scores {1} points.", args[0], CalculateWordValue(args[0]));
    }

    public static Dictionary<char, int> wordValues = new Dictionary<char, int>()
    {
        { 'a', 1 }, { 'b', 3 }, { 'c', 3 }, { 'd', 2 }, { 'e', 1 }, { 'f', 4 }, { 'g', 2 }, { 'h', 4 }, { 'i', 1 },
        { 'j', 8 }, { 'k', 5 }, { 'l', 1 }, { 'm', 3 }, { 'n', 1 }, { 'o', 1 }, { 'p', 3 }, { 'q', 10 },{ 'r', 1 },
        { 's', 1 }, { 't', 1 }, { 'u', 1 }, { 'v', 4 }, { 'w', 4 }, { 'x', 8 }, { 'y', 4 }, { 'z', 10 }
    };

    public static int CalculateWordValue(string word)
    {
        word = word.ToLower();
        int totalScore = 0;

        foreach(char ch in word)
        {
            int chScore = 0;
            if(wordValues.TryGetValue(ch, out chScore))
            {
                totalScore += chScore;
            }
        }

        return totalScore;
    }
}

(pastebin, 32 bit binary)

2.3: Scrabble™ Validity Tester

Description

Staying with Scrabble. A standardScrabble&153; set contains the following set of tiles: A-9. B-2. C-2. D-4. E-12. F-2. G-3. H-2. I-9. J-1. K-1. L-4. M-2. N-6. O-8. P-2. Q-1. R-6. S-4. T-6. U-4. V-2.

Plus two blanks which can be assigned any letter when they are played.

For extra bonus points you could improve your program so that it indicates whether or not the word could actually entered during the game. The program could also indicate whether or not a blank tile is required.

My Solution

The problem description is missing some of the tile counts for me, so I am using data from [this website]. I tried to compact the array of tile counts for this one, but it didn't work too well because I ended up writing more code to read the array than I saved by compacting it.....

using System;
using System.Collections.Generic;

class ScrabbleValidator
{
    // from http://scrabblewizard.com/scrabble-tile-distribution/
    // the coding conundrums seems to have a few letter counts missing
    public static string[] letterCounts = new string[]
    {
        "", // 0
        "jkqxz", // 1
        "bcfhmpvwy*", // 2 - * = blank tile
        "g", // 3
        "dlsu", // 4
        "", // 5
        "nrt", // 6
        "", // 7
        "o", // 8
        "ai", // 9
        "", // 10
        "", // 11
        "e", // 12
    };

    public static int blankTileCount = 2;

    static void Main(string[] args)
    {
        if(args.Length != 1)
        {
            Console.WriteLine("This program works out whether a word is a valid scrabble word.");
            Console.WriteLine("Use it like this:");
            Console.WriteLine("    ScrabbleValidator.exe <word>");

            Console.WriteLine("\n<word>: The word you want to validate.");
            return;
        }

        string word = args[0].Trim().ToLower();

        // count the number of each letter in the word
        Dictionary<char, int> letterCounts = new Dictionary<char, int>();
        foreach (char ch in word)
        {
            if (letterCounts.ContainsKey(ch))
            {
                letterCounts[ch] += 1;
            }
            else
            {
                letterCounts.Add(ch, 1);
            }
        }

        // loop over the letter counts and validate the word
        string invalidReasons = "";
        int usedBlanks = 0;
        foreach (KeyValuePair<char, int> letterCount in letterCounts)
        {
            char currentChar = letterCount.Key;
            int currentCharCount = letterCount.Value;
            int maxCharCount = getLetterCount(currentChar);

            if (currentCharCount > maxCharCount)
            {
                if(usedBlanks + (currentCharCount - maxCharCount) <= blankTileCount)
                {
                    usedBlanks += currentCharCount - maxCharCount;
                }
                else
                {
                    invalidReasons += String.Format("The character '{0}' is used {1} times (scrabble has {2} tiles for that letter).\n", currentChar, currentCharCount, maxCharCount);
                }
            }
        }

        if(invalidReasons.Length > 0)
        {
            Console.WriteLine("{0} is not valid. Reasons: ", word);
            Console.WriteLine(invalidReasons);
        }
        else
        {
            Console.WriteLine("{0} is a valid scrabble word.", word);
            Console.WriteLine("It would use {0} blank tiles.", usedBlanks);
        }
    }

    static int getLetterCount(char ch)
    {
        for(int i = 0; i < letterCounts.Length; i++)
        {
            if(letterCounts[i].Contains(Char.ToLower(ch).ToString()))
            {
                return i;
            }
        }
        return 0; // the character wasn't recognised, so there won't be any tiles that match it.
    }
}

(pastebin, 32 bit binary)

Note that I don't have any analytics on this site yet, so the only way I know you have been here at all is through the comments (and the server logs).

Coding Conundrums 1

This is the 50th post I have written for this blog! (There are a few posts scheduled to be released, so you may not be able to see posts #48 and #49 at the time of this post's release) This is also the first time I am trying to insert a post before two scheduled posts. Hopefully they come out in the right order.

Recently Rob Miles has released the first of a series of problem problems called "Coding Conundrums" with this tagline:

Number one in a series of more than one. Probably.

I have decided to write solutions for these problems and post them here on my blog for you. Each solution comes with it's associated description, a pastebin link, and a link to a compiled 32 bit binary (other types of binary are available, just ask in the comments).

1.1: Sequence Reversal

The challenge:

I want a program that reads in 10 numbers and prints them out in the reverse order to the order they were entered. I've no idea why I want this, I just do.

My solution:

using System;

class Program
{
    public static void Main(string[] args)
    {
        if(args.Length != 10)
        {
            Console.WriteLine("Coding Conundrums Problem 1.1 Solution: Sequence Reversal");
            Console.WriteLine("---------------------------------------------------------");
            Console.WriteLine("Problem Description:");
            Console.WriteLine("    I want a program that reads in 10 numbers and prints them out");
            Console.WriteLine("    in the reverse order to the order they were entered.");
            Console.WriteLine();
            Console.WriteLine("(You entered {0} numbers)", args.Length);
            Console.WriteLine();
            Console.WriteLine("Use it like this: ");
            Console.WriteLine("    sequencereverse.exe 1 2 3 4 5 6 7 8 9 10");

            return;
        }

        int[] numbers = new int[args.Length];
        for(int i = 0; i < args.Length; i++)
        {
            if(!int.TryParse(args[i], out numbers[i]))
            {
                Console.WriteLine("Error: {0} is not a number.", args[i]);
                return;
            }
        }
        Array.Reverse(numbers);

        for(int j = 0; j < numbers.Length; j++)
        {
            Console.Write("{0} ", numbers[j]);
        }
        Console.WriteLine();
    }
}

(Pastebin, 32 bit Binary)

1.2: Number Shuffle

Problem Description:

I want a program that will print outthe numbers 1,2,3,4,5,6,7,8,9 in a shuffled order. The order must be different each time the program runs. Note that the same number must be different each time. It should be possible to extend this to work with 52 numbers, in which case I can make a shuffled deck of cards.

My solution:

using System;

class Program
{
    public static void PrintHelp()
    {
        Console.WriteLine("Coding Conundrums Problem 1.2 Solution: Number Shuffle");
        Console.WriteLine("------------------------------------------------------");
        Console.WriteLine("Problem Description:");
        Console.WriteLine("    I want a program that will print outthe numbers 1,2,3,4,5,6,7,8,9 in a");
        Console.WriteLine("    shuffled order. The order must be different each time the program runs. Note");
        Console.WriteLine("    that the same number must be different each time. It should be possible to");
        Console.WriteLine("    extend this to work with 52 numbers, in which case I can make a shuffled");
        Console.WriteLine("    deck of cards.");
        Console.WriteLine();
        Console.WriteLine("Use it like this: ");
        Console.WriteLine("    numbershuffle.exe <count-to>");
        Console.WriteLine();
        Console.WriteLine("Paramters:");
        Console.WriteLine("    <count-to>: The number to count up to when generating the initial sequence of numbers.");
    }

    public static void Main(string[] args)
    {
        if(args.Length != 1)
        {
            PrintHelp();
            return;
        }

        int numberCount;
        if(!int.TryParse(args[0], out numberCount))
        {
            PrintHelp();
            return;
        }

        int[] numbers = new int[numberCount];
        for(int i = 0; i < numberCount; i++)
        {
            numbers[i] = i + 1;
        }

        int swapsCount = numberCount * 2;
        int temp, a, b;
        Random random = new Random();
        for(int i = 0; i < swapsCount; i++)
        {
            a = random.Next(numbers.Length);
            b = random.Next(numbers.Length);

            temp = numbers[a];
            numbers[a] = numbers[b];
            numbers[b] = temp;
        }

        for(int i = 0; i < numbers.Length; i++)
        {
            Console.Write("{0} ", numbers[i]);
        }
    }
}

(pastebin, 32 bit binary)

1.3: Shoe Popularity Contest

Problem Description:

I want a program that reads in 20 integers and tells me how much of each number was entered. I actually have a use for this, in that each day I sell 20 pairs of shoes and I want to find out the most popular shoe sizes

My solution:

I looked up and used a C♯ Dictionary for this one.

using System;
using System.Collections.Generic;

class Program
{
    public static void PrintHelp()
    {
        Console.WriteLine("Coding Conundrums Problem 1.2 Solution: Number Shuffle");
        Console.WriteLine("------------------------------------------------------");
        Console.WriteLine("Problem Description:");
        Console.WriteLine("    I want a program that reads in 20 integers and tells me how much of each number");
        Console.WriteLine("    was entered. I actually have a use for this, in that each day I sell 20 pairs of");
        Console.WriteLine("    shoes and I want to find out the most popular shoe sizes. It's amazing that I");
        Console.WriteLine("    manage to hold down my lecturing job, what with all the shoe sales I'm involved");
        Console.WriteLine("    with.");
        Console.WriteLine();
        Console.WriteLine("Use it like this: ");
        Console.WriteLine("    shoesales.exe");
    }

    ///<summary>
    ///Gets an integer from the user between min and max inclusive.
    ///</summary>
    ///<param name="prompt">The prompt to display to the user.</param>
    ///<param name="min">The minimum value the user should enter.</param>
    ///<param name="max">The maximum value the user should enter.</param>
    static int ReadNumber(string prompt, int min, int max)
    {
        int number;
        while (true)
        {
            Console.Write(prompt);
            try
            {
                number = int.Parse(Console.ReadLine().Trim());
            }
            catch
            {
                Console.WriteLine("That was not a number. Numbers may contain numeric characters only.");
                continue;
            }

            if (number < min)
            {
                Console.WriteLine("That number was too low. Please enter a number between " + min + " and " + max + ".");
                continue;
            }
            if (number > max)
            {
                Console.WriteLine("That number was too high. Please enter a number between " + min + " and " + max + ".");
                continue;
            }

            break;
        }

        return number;
    }

    public static void PrintShoeSizes(Dictionary<int, int> shoes)
    {
        Console.WriteLine("Shoe Sizes:");
        Console.WriteLine("-----------");
        Console.WriteLine("Size     Count");
        foreach(KeyValuePair<int, int> shoeSize in shoes)
        {
            Console.WriteLine("{0,-8} {1}", shoeSize.Key, shoeSize.Value);
        }
    }

    public static void Main(string[] args)
    {
        if(args.Length == 1 && args[0].ToLower().Trim('-') == "help")
        {
            PrintHelp();
            return;
        }

        int shoeTotal = 20;

        Dictionary<int, int> shoes = new Dictionary<int, int>();
        for(int i = 0; i < shoeTotal; i++)
        {
            PrintShoeSizes(shoes);
            int currentShoeSize = ReadNumber(String.Format("Enter the shoe size #{0}: ", i + 1), 1, 12);

            if(!shoes.ContainsKey(currentShoeSize))
            {
                shoes.Add(currentShoeSize, 1);
            }
            else
            {
                shoes[currentShoeSize] += 1;
            }
        }
    }
}

(pastebin, 32 bit binary)

Art by Mythdael