Sunday, March 30, 2014

Problem 79 - Java, aka fun with HashSets

So, as it was free, I solved problem 79 in Java. Things weren't that bad, and my aversion to Java for the past year and a half or so made me actually pleasantly surprised to find that it wasn't too bad to work with the language, even though I will admit that Vector<HashSet<Integer>> is a lot of boilerplate, but nonetheless, having sets available was good for this problem. Nothing too special, runs in .134 seconds on my machine. Also, notably, my solution depends on the fact that there are no duplicate numbers in the answer, things would be a bit harder if those were allowed.

import java.util.Scanner;
import java.util.HashSet;
import java.util.Vector;

public class e79 {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        Vector<HashSet<Integer>> preceding = Vector<HashSet<Integer>>();
        HashSet<Integer> used = new HashSet<Integer>();
        for (int i = 0; i < 10; ++i) {
            preceding.add(new HashSet<Integer>());
        } 
        while (scan.hasNextInt()) {
            int entry = scan.nextInt();
            Integer d1 = entry / 100;
            Integer d2 = (entry / 10) % 10;
            Integer d3 = entry % 10;
            preceding.get(d2).add(d1);
            preceding.get(d3).add(d1);
            preceding.get(d3).add(d2);
            used.add(d1);
            used.add(d2);
            used.add(d3);
        }
        String ans = "";
        int i = 0;
        while (i < 10) {
            if (preceding.get(i).isEmpty() && used.contains(i)) {
                ans += i;
                used.remove(i);
                for (HashSet<Integer> hs : preceding) {
                    hs.remove(i);
                }
                i = 0;
            } else {
                ++i;
            }
        }
        System.out.println(ans);
    }
}

Friday, March 28, 2014

A single letter and bringing back an old friend - Problem 20 in E

There are a lot of languages with single letter names. To name just the ones used so far in this language challenge, C,D,J,K,R are all languages, and F# deserves an honorable mention. Even the letters that are not associated with languages too many people care about are associated with languages though, as I learned today with E. The hardest part of E was figuring out how to do anything without very much documentation to rely on, but once I figured out how to do things, there wasn't too much issue. The last time I solved problem 20 was way back in the 24-hour 20-problem hackathon that began all of this, and as it was towards the end of the hackathon, I threw a capable language at it, despite it being an easy problem. However, that capable language was Java, which, though I took a semester-long class taught in it, is not exactly my favorite language. However, using it in problem 20 simply because it had the BigInteger class was a bit silly. So, I have now recovered problem 20, and I did so without relying on anything like a BigInteger, instead explicitly storing the big number as an array of digits and doing some work by hand. So, problem 20 is solved, E is used, and Java is free. Solution runs in about 4.8 seconds on my machine, but the E interpreter has such a slow start up time that Hello World runs in about 4.1 seconds, so timing is pretty unreliable.
var d := [1]
def digits := d.diverge()


for x in 2..100 {
    var carry := 0
    for i in 0..(digits.size()-1) {
        var prod := (digits[i] * x) + carry
        digits[i] := prod % 10
        carry := prod // 10
    }
    while (carry > 0) {
        digits.push( carry % 10)
        carry := carry // 10
    }
}

var digisum := 0

for d in digits {
    digisum += d
}

println(digisum)


Thursday, March 27, 2014

Problem 78 - R

So, after solving problem 45 in Rexx, I had R open and free for use. Problem 78 was a bit annoying for me. Problem 76, I decided to solve using dynamic programming as it was pretty easy to do so, and that solution generalized really well to problem 77. There was another way to solve problem 76, and that was by directly calculating the partition function called p(n) in this problem. I realized that this was what I had to do, but mathworld and wikipedia are not the best place to learn this things (and my copy of TAOPC is up at college, far from my hands), and they were not very clear what conventions were being used or what bounds were reasonable for the sum that must be calculated. My first solution took 67 minutes in Python, and then after the change to the loop bounds, in took 9 seconds. After I ported my solution to R, it took about 4 minutes to calculate the answer, but I am okay with that, according to the first estimate I looked at, about 20x slowdowns are expected moving to R from Python, and Python is already about 20x slower than C, so 4 minutes in a language like R feels like it is fair to consider it within Project Euler's one minute rule. Anyway, here is my solution, which took a while to debug off-by-one errors resulting from arrays starting with index 1.
N = 100000
p <- array(0, dim=c(N))

p[1] <- 1
p[2] <- 1
for (n in 2:N) {
    n1 <- 1
    n2 <- 1
    k  <- 1
    while (n1 > 0 || n2 > 0) {
        n1 <- n - (k*(3*k-1)) %/% 2
        n2 <- n - (k*(3*k+1)) %/% 2
        c  <- 0
        if (n1 >= 0) {
            c <- p[n1+1]
        }
        if (n2 >= 0) {
            c <- c + p[n2+1]
        }
        if (k %% 2 == 0) {
            c <- c * -1
        }
        p[n+1] <- (p[n+1] + c) %% 1000000
        k <- k + 1
    }
    if (p[n+1] == 0) {
        print(n)
        break
    }
}

Wednesday, March 26, 2014

Rexx to get R (45)

I want to move on to solve problem 78, but it is another dynamic programming problem, and therefore I would really like a language in which arrays are pretty easy to use. Admittedly, I haven't actually looked much at R, but it feels like a language that should have pretty good support for arrays, seeing as people use it for processing large data sets and stuff. So, the language I used for problem 45 is a language called Rexx (note: do not make the mistake I made and append an extra x to the end of the name while searching for it!) According to http://langpop.com/, it is so popular that it just barely edges out brainfuck. Anyway, here is my wonderful solution, it is little more than a transcription of my old R code to Rexx, but it notably includes yet another implementation of the babylonian method for sqrt: maybe after the 20th time I will finally stop needing to consult wikipedia to remember how to do that.
Solution runs in 1.7s on my computer:
numeric digits 20

i = 144
do forever
h = hex(i)
if isPent(h) then
do
say h
leave
end
i = i + 1
end

isPent:
parse arg p
a = sqrt(24*p+1)
return (a*a = 24*p+1) & ((a+1) // 6 = 0)

hex:
parse arg n
return n*(2*n-1)

sqrt:
parse arg N
x1 = N % 2
x2 = N
do while (x2 - x1) > 1
x2 = x1
x1 = (x1 + (N % x1) ) % 2
end
return x2


Hack 77 - I didn't lie

I solved problem 77 in a language called Hack (hacklang.org), which, in the trend of languages that attempt to be "language X but with change Y", is an attempt at making a better version of PHP where it is harder to shoot yourself in the foot. It has type annotations, so it might succeed at that, though I didn't have enough time to see if those annotations actually lead to good static type checking. Anyway, Problem 77 is the type of problem that, if I didn't have to switch languages all the time, would have taken very little effort, but it still didn't take that much effort because it was pretty easy to create my solution to this problem from the last. Still dynamic programming, still similar probably of counting the ways to write a number as a sum. Because I had a pretty crazily high upper bound on my search (1000), this runs in .4s on my machine, searching only up to 100 gives a 4x speedup. Even though I haven't used PHP much, didn't have too many problems with Hack: main problems were a) it took something like 5 hours to install, b) Forget semicolons as I was moving from Python and Forth, and c) Of course I dropped some $'s, I personally think that if I were to make a "better PHP", the $'s would have been one of the first things I would have cut, it seems pretty clear from all the non-Perl, non-PHP languages out there that people generally don't want/need special characters to denote variables. (Also, no, that is not a typo, hack files begin with <?hh but have no closing >).
<?hh

function isPrime(int $x): int {
    if ($x < 2) {
        return false;
    } else if ($x % 2 == 0) {
        return $x == 2;
    }

    for ($i = 3; $i*$i <= $x; $i+=2) {
        if ($x % $i == 0) {
            return false;
        }
    }
    return true;
}

$count = Vector<Vector<int>>{ } ;
$BOUND = 1000;

for ($i = 0; $i < $BOUND; $i++) {
    $count[] = Vector<int>{};
    for ($j = 0; $j < $BOUND; $j++) {
        $count[$i][] = 0;
    }
}

for ($i = 0; $i < $BOUND; $i++) {
    for ($j = 0; $j < $BOUND; $j++) {
        if ($i == 2 or ($j == 2 and $i % 2 == 0)) {
            $count[$i][$j] = 1;
        } else if ($i < 2 or $j < 2) {
            $count[$i][$j] = 0;
        } else if ($j >= $i) {
            $count[$i][$j] = $count[$i][$i-1];
            if (isPrime($i)) {
                $count[$i][$j] += 1;
            }
        } else if (isPrime($j)) {
            $count[$i][$j] = $count[$i - $j][$j] + $count[$i][$j - 1];
            if ($count[$i][$j] > 5000) {
                echo $i . "\n";
                $i = $BOUND;
                $j = $BOUND;
            }
        } else {
            $count[$i][$j] = $count[$i][$j - 1];
        }
    }
}


Tuesday, March 25, 2014

Progress

Below is the table of my progress. It includes all of the languages that I have solved problems in, as well as which problem I solved in that language. Statements of the problems can be found at projecteuler.net, and all of the solutions are linked to from the table, in addition to being directly in posts on this blog.
BrainFuck 1*
Haskell 2*,37
J 3*,24*,35*
J 69*,72
Ruby 4*,40*,56
Whenever 2,5*
Ook! 6*
Racket 7*,26*,57
K 8*,30
Javascript 9*,31*,60
sML 10*,42
PHP 11
Go 12*,32
cLisp 13*,62
C 48*,50
Fortran95 3,15*
Python 16*,24*,39*
Python 65*,66
ELM 17*,48
Scala 18*,44
Perl 19*,70
Java 20*,79
FALSE 4
Squirrel 21*,52*,55
D 22
Ceylon 23
Postscript 7
Befunge 27
Boo 29
Frink 16*,80
Forth 9*,76
Shakespeare 12
Bash 33
Batch 34
Whitespace 36
LOLCODE 10
Lua 38
Erlang 24
Rust 40
Ada 41
Clojure 14
Coffeescript 43
Prolog 18*,67
R 45*,78
Julia 46
x86-64 47
INTERCAL 17
OCaml 49
COBOL 21
Cobra 51
C++ 14*,53
APL 52
Chapel 54
C# 26*,59
WARM 58
Kotlin 26
Pascal 61
ALGOL68 31
Smalltalk 13
Dart 63*,65
Tcl 64
Gosu 39
Rebol 63
WIND 18
ChucK 35
F# 19
Fantom 68
Processing 71
Groovy 73
Genie 74
Vala 75
ArnoldC 9
Hack 77
Rexx 45
E 20
BASIC 16
Dogescript 81
Analytic 1,5,6,8
Analytic 15,25,28,69

Spring Break - Problem 76 in Forth

Yet again, a problem solved after a long hiatus: hopefully the distance between this solution and the next will be less than the distance between it and the previous, as I am now on a two-week long Spring Break, a perfect time to solve some Project Euler problems. Today, I used Forth, which I hadn't used since problem 9, and there I really only used it as a glorified postscript. This time around, I used some of the more interesting features of the language, like actually using data structures, in this case a big "two dimensional" (that was two hard, so its just a one dimensional and I convert indices between 1 and 2 dimensions) array which I use to solve the problem: We just covered Dynamic Programming in my Algorithms class, and Project Euler 76 happens to be a wonderful problem for Dynamic Programming. Now, the combination of the fact that the solution was found through dynamic programming and the fact that it is written in Forth may make the solution unintelligible to most looking at it, but oh well, and I will admit I had to work through the solution in Python before converting it over to Forth. Here is my solution, runs in about 80ms on my machine.
create count 101 101 * cells allot
: splitIndex { x } x 101 mod x 101 / ;
: makeIndex { i j } 101 j * i + ;
: test1 { i j } i 1 = j 1 = or ;
: test0 { i j } i 0 = j 0 = or ;
: testbig { i j } j i >= ;
: setArray { index value } value count index cells + ! ;
: getArray { index } count index cells + @ ;
: computeAns { i j } i j - j makeIndex getArray i j 1 - 
makeIndex getArray +  ;
: main 0 begin  
dup splitIndex test1 if dup 1 setArray else 
dup splitIndex test0 if dup 0 setArray else
dup splitIndex testbig if dup dup splitIndex drop dup 1 - 
makeIndex getArray 1 + setArray else
dup dup splitIndex computeAns setArray then then then 
1 + dup 101 101 * = until 
100 99 makeIndex getArray CR . CR bye ;
main

Thursday, March 6, 2014

Long break due to school, but here is some Arnold

A friend of mine showed me a language called ArnoldC (https://github.com/lhartikk/ArnoldC). This wonderful language requires commands to be written in the language of Arnold Schwarzenegger quotes. Though it was a very fun language to work with, I have a slight confession regarding this problem, the program doesn't quite print out the answer. The problem asks for you to find a pythagorean triple (a,b,c) and the answer is then the product abc. The product abc is too large to store in ArnoldC's 16bit integers, so I just print the triple from this program and multiply on a calculator. I normal dislike intermediary answers, but this feels entirely sufficient - for what it's worth, it's less effort converting the answer this way than it was extracting the decimal answer from the brainF unary output I had a while ago. Despite needing to put up with Arnold, this solution is relatively fast - runs in .110s on my machine.
LISTEN TO ME VERY CAREFULLY sqrt
I NEED YOUR CLOTHES YOUR BOOTS AND YOUR MOTORCYCLE x
GIVE THESE PEOPLE AIR
HEY CHRISTMAS TREE prev
YOU SET US UP 0
GET TO THE CHOPPER prev
HERE IS MY INVITATION  x
HE HAD TO SPLIT 2
ENOUGH TALK
HEY CHRISTMAS TREE current
YOU SET US UP prev
HEY CHRISTMAS TREE continue
YOU SET US UP 1
HEY CHRISTMAS TREE result
YOU SET US UP 1
HEY CHRISTMAS TREE diff
YOU SET US UP 1
STICK AROUND continue

GET TO THE CHOPPER prev
HERE IS MY INVITATION current
ENOUGH TALK

GET TO THE CHOPPER current
HERE IS MY INVITATION x
HE HAD TO SPLIT current
GET UP prev
HE HAD TO SPLIT 2
ENOUGH TALK

GET TO THE CHOPPER diff
HERE IS MY INVITATION current
GET DOWN prev
ENOUGH TALK

GET TO THE CHOPPER result
HERE IS MY INVITATION diff
YOU ARE NOT YOU YOU ARE ME 0
ENOUGH TALK

BECAUSE I'M GOING TO SAY PLEASE result
GET TO THE CHOPPER continue
HERE IS MY INVITATION 0
ENOUGH TALK
YOU HAVE NO RESPECT FOR LOGIC

GET TO THE CHOPPER result
HERE IS MY INVITATION diff
YOU ARE NOT YOU YOU ARE ME 1
ENOUGH TALK

BECAUSE I'M GOING TO SAY PLEASE result
GET TO THE CHOPPER continue
HERE IS MY INVITATION 0
ENOUGH TALK
YOU HAVE NO RESPECT FOR LOGIC

CHILL

I'LL BE BACK current
HASTA LA VISTA, BABY

IT'S SHOWTIME

HEY CHRISTMAS TREE a
YOU SET US UP 2
HEY CHRISTMAS TREE b
YOU SET US UP 7
HEY CHRISTMAS TREE a2
YOU SET US UP 0
HEY CHRISTMAS TREE b2
YOU SET US UP 0
HEY CHRISTMAS TREE c2
YOU SET US UP 0
HEY CHRISTMAS TREE c
YOU SET US UP 0
HEY CHRISTMAS TREE t1
YOU SET US UP 0
HEY CHRISTMAS TREE t2
YOU SET US UP 0
HEY CHRISTMAS TREE result
YOU SET US UP 1
HEY CHRISTMAS TREE always
YOU SET US UP 1

STICK AROUND always
STICK AROUND result
GET TO THE CHOPPER a2
HERE IS MY INVITATION a
YOU'RE FIRED a
ENOUGH TALK

GET TO THE CHOPPER b2
HERE IS MY INVITATION b
YOU'RE FIRED b
ENOUGH TALK

GET TO THE CHOPPER c2
HERE IS MY INVITATION a2
GET UP b2
ENOUGH TALK

GET YOUR ASS TO MARS c
DO IT NOW sqrt c2

GET TO THE CHOPPER result
HERE IS MY INVITATION c
YOU'RE FIRED c
YOU ARE NOT YOU YOU ARE ME c2
ENOUGH TALK

BECAUSE I'M GOING TO SAY PLEASE result
GET TO THE CHOPPER result
HERE IS MY INVITATION a
GET UP b
GET UP c
YOU ARE NOT YOU YOU ARE ME 1000
ENOUGH TALK
BECAUSE I'M GOING TO SAY PLEASE result
TALK TO THE HAND a
TALK TO THE HAND b
TALK TO THE HAND c
GET TO THE CHOPPER always
HERE IS MY INVITATION 0
ENOUGH TALK
GET TO THE CHOPPER a
HERE IS MY INVITATION 499
ENOUGH TALK
YOU HAVE NO RESPECT FOR LOGIC
YOU HAVE NO RESPECT FOR LOGIC

GET TO THE CHOPPER a
HERE IS MY INVITATION a
GET UP 1
ENOUGH TALK

GET TO THE CHOPPER result
HERE IS MY INVITATION 500
LET OFF SOME STEAM BENNET a
ENOUGH TALK
CHILL

GET TO THE CHOPPER a
HERE IS MY INVITATION 1
ENOUGH TALK
GET TO THE CHOPPER b
HERE IS MY INVITATION b
GET UP 1
ENOUGH TALK
GET TO THE CHOPPER result
HERE IS MY INVITATION 1
ENOUGH TALK
CHILL
YOU HAVE BEEN TERMINATED