3n + 1 in Erlang

This is my second Programming Challenges solution written in Erlang. First here.

This time I chose the first problem 3n + 1 #110101.

It is a little bit of a cheat doing it in Erlang, as the major point of the original problem is knowing the limits of your data types, and thus C’s int type is not large enough to manage the problem. I am not even sure is a int64 is large enough or if you need to drop down to your own large number type. Ether way,  Erlang does not suffer from this problem with it’s dynamic size number type.

So here is my solution:

-module(threenplusone).
-export([three_n_plus_one_range/2,test/0]).

three_n_plus_one_range(Min, Max) ->
    lists:max([threenplusone(X) || X <- lists:seq(Min, Max) ]).

threenplusone(Num) ->
    threenplusone(Num, 1)

threenplusone(1, Count) -> Count;
threenplusone(Num, Count) ->
    case (Num rem 2) of
        1 -> threenplusone( (Num * 3) + 1, Count + 1);
        0 -> threenplusone( Num div 2, Count + 1)
    end.

test() ->
    20 = three_n_plus_one_range(1,10),
    125 = three_n_plus_one_range(100, 200),
    89 = three_n_plus_one_range(201, 210),
    174 = three_n_plus_one_range(900,1000),
    true.

The problem states that numbers up to 1,000,000 are known to converge to 1, so I ran the problem from 1 -> 1,000,000 and the largest number of steps is 525. This took around 10 seconds on my MacBook which I feel is performant enough.

I quite like using the lists:seq generator and the list comprehension together, but I wonder if there is a better way to-do number generation and function calling in a single line.

Reverse And Add 110502 in Erlang

Carrying on from Cedric’s Challenge (C#, Erlang) I decided to do some of the Programming Challenges problems in Erlang, because the problems are small, but fun.

My first is Reverse And Add #110502 and here is my solution:

-module(revandadd).
-export([rev_and_add/1, test/0]).%% number to list
ntl(Num) ->
    ntl(Num, []).
ntl(0, List) ->
    List;

ntl(Num, List) ->
    ntl(Num div 10, [Num rem 10]++List).

%% list to number
ltn(List) ->
    ltn(List, 0).

ltn([], Num) ->
    Num;
ltn([H|T], Num) ->
    ltn(T, (Num*10)+H).

%% is palindrome
is_pal(Num) ->
    ntl(Num) == lists:reverse(ntl(Num)).

rev_and_add(Num) ->
    rev_and_add(Num, 1).

rev_and_add(Num, Count) ->
    Pal = ltn(lists:reverse(ntl(Num))) + Num,
    case is_pal(Pal) of
    true ->
        [Count,Pal];
    false ->
        rev_and_add(Pal, Count+1)
    end.

test() ->
[4,9339] = rev_and_add(195),
[5,45254] = rev_and_add(265),
[3,6666] = rev_and_add(750),
true.

I’m not too happy with the number-to-list functions as I’m sure there should be a built in way to-do this already, which Joe implies therefore there probably is.

Cedric’s Coding challenge - An Erlang solution

So after the verbosity of my C# Solution I was wanting a neat solution, and was hoping that Erlang would deliver:

-module(challenge).
-export([main/0]).

main() ->
    [worker(X, 0, [], [1,2,3,4,5,6,7,8,9]) || X <- [1,10,100,1000,10000,100000,1000000,10000000,100000000]],
    true.

worker(Mod, Number, Used, ToUse) ->
    if
        Mod == 1 ->
            [Number+X || X <- ToUse];
        true ->
            [worker(Mod div 10, Number+(X*Mod), [X]++Used, ([0,1,2,3,4,5,6,7,8,9]--Used)--[X]) || X <- ToUse]
    end.

I feel this is pretty good. To get the results just remove the “true.“ statement from main().

Unfortunately it is not as fast as I would like, taking 5 seconds to run, but I’m not sure I’m using lists in the smartest way..

Nothing left to read

This is a first, I have nothing to read in FeedDemon:

Nothing to read
Nothing to read

I prefer to think that the Internet is broken, and that’s why I have nothing to read, or the authors of most of the blog’s I read are sick.

But what I do know, is that it has nothing to-do with how mind numbing my current work is….. honest.

Actually it’s more likely because I have not gone swimming for the last three weeks and have been at my desk most lunchtimes and therefore keeping up with my feeds.

Cedric’s Coding challenge

I noticed Cedric’s Coding challenge while reading Robert Fisher’s blog.

Here is an interesting coding challenge: write a counter function that counts from 1 to max but only returns numbers whose digits don’t repeat.

For example, part of the output would be:

  • 8, 9, 10, 12 (11 is not valid)
  • 98, 102, 103 (99, 100 and 101 are not valid)
  • 5432, 5436, 5437 (5433, 5434 and 5435 are not valid)

Also:

  • Display the biggest jump (in the sequences above, it’s 4: 98 -> 102)
  • Display the total count of numbers
  • Give these two values for max=10000

Because I love coding problems, I whipped up a C# 2.0 solution which is not as succinct as some of the functional solutions, but it works on a ‘fast enough for me’ time scale.

using System;
using System.Collections.Generic;
using System.Diagnostics;

namespace ConsoleApplication1
{
  class Program
  {
    static bool[] used = new bool[10];
    static int value = 0;

    static void Main(string[] args)
    {
      int gap = 0;
      int last = 0;
      int count = 0;
      Stopwatch timer = new Stopwatch();

      timer.Start();
      int mag = 1;
      for (int i = 1; i < 10; i++)
      {
        foreach (int x in Step(1, mag))
        {
          gap = Math.Max(gap, x - last);
          last = x;
          count++;
        }

        mag *= 10;
      }
      timer.Stop();
      Console.WriteLine("Count: {0}", count);
      Console.WriteLine("Gap: {0}", gap);
      Console.WriteLine("Time: {0}", timer.Elapsed);
      Console.ReadKey();
    }

    static IEnumerable<int> Step(int start, int mag)
    {
      for (int i = start; i < 10; i++)
      {
        if (used[i] == false)
        {
          if (mag == 1)
          {
            yield return value + i;
          }
          else
          {
            used[i] = true;
            value += mag * i;

            foreach (int x in Step(0, mag / 10))
            {
              yield return x;
            }

            used[i] = false;
            value -= mag * i;
          }
        }
      }
    }
  }
}

Giving the following output (for 1 - MaxIn, as compared to 1-10,000 in the original challenge)

Count: 5611770
Gap: 10469135
Time: 00:00:02.8350765

Curse of the Azure Bonds - build 1.0.11

Installer 1.0.11 is now released.
Issues fixed in this build are:

  • Fixed crash, caused by trying to load the 8 frame Medusa animation - Issue 27
  • Using the ‘Dust of Disappearance’ crashed the game in casting stage
  • Displaying magic effects after using the ‘Dust of Disappearance’ showed Invisible as well as <no spell effects>
  • Effects were not restored correctly from a saved game
  • Player items were loaded in the opposite order compared to the DOS version
  • Effects were wearing off too quickly. In the Mulmaster Beholder Corps battle the Dust was gone after round 3

As always, progress is slow but steady, and I have started playing the game from the beginning to check that the game is playable.

BSOD on MacBook

I was just playing my Curse of the Azure Bonds port, checking that the game can be played through, when Windows ‘Blue Screen of Death’.  It was a very rude feeling, as I have not seen a BSOD for years, well at least that’s how it feels.

I’m feeling really cheated on the gaming front, because I had gotten into the third zone of the fire knives, and hadn’t saved since starting the game, so lost heaps of progress….

At least Windows kept the dump files, and uploaded them so it might get fixed. The next part always make me laugh, you get taken to a Microsoft page where you get told, “sorry there is not a lot we can do about that…” and then they ask if that was helpful…  sure was!

There is an update from Apple for ‘BootCamp Installs’ which is installing right now, but I had to stop playing my game, as the Installer keep grabbing focus, which gets annoying quickly.

Well it wants to reboot now, so I’ll have to go.

It’s back, and now installing Service Pack 3 for XP, so my evening is over.

Post #500, Well really #392

According to the Wordpress post management screen, this post will be post #500, yet the dashboard says I only have 391 actual posts.  Not sure what has happened to the other 108 posts.

But whether or not this post is number 500, it does mark a new milestone.  I have confessed my shame over my useless writing/grammar/spelling skills to Michaela, who has very kindly offered to be my editor.

Here are some examples of noticed mistakes:

Intended Word Used Word
were where
seem seam
which witch
whether weather
sweet sweat

This excludes my over use of commas, and general missing of tiny words from long sentences.

So moving forward, my posts will hopefully be less incomprehensible dribble, and just dribble.