Friday, August 30, 2013

Batch - Bash was nice enough, so why not... (Problem 34)

Well, yesterday I solved problem 33 in Bash, and that was a walk in the park compared to a lot of things I have had to do for this challenge. I decided that if Bash could be so relatively nice to work with, with tons of features that make programming nice - functions, good support for arithmetic, etc. - how bad could the Windows scripting equivalent, Batch be, even if I have heard many bad things about it? Turns out it can be pretty bad. First of all, I had some difficulty getting off the ground working on this problem - apparently neither dosbox nor wine cmd.exe correctly emulate batch file interpreting on Linux, so after a while trying to get those to work I had to move to a Windows computer to do the rest of my work. Once there, things seemed to be going swimmingly (after getting used to the annoying syntax of %..% for variable accesses and needing to use "set /a" for all assignments...this made me miss the $var notation I previously hated in bash and PHP), until I noticed that my program ran far, far more slowly than it should...it took about 30 seconds to test numbers from 1 to 1000, so then I had to fix my solution to be less brute-forcing...which led to the wonderful mess that is my program below, due to batch's lack of full support for for loops...(for loops can't have labels in them...and there was basically no way to do what I needed to do without a goto or two), so now my code has 10-fold nested loops implemented with gotos...fun stuff. despite all my work to make it run faster, this still takes about 20 seconds on my machine to find the correct answer (Windows doesn't have the nice command-line "time" command, and I didn't feel like taking the time to do more precise timing)

Anyway, despite the difficulties, I am now done with problem 34 and with trying to write project euler solution type problems in batch.
Also, I am pretty sure this program now takes the prize for most lines of code I have written for a solution for this challenge. (not counting the writing of the Shakespeare compiler)
@echo off
goto main

rem  *I originally wrote this factorial method, but it
rem  *is slower than the lookup method, which is plenty
rem  *suitable for the needs of this problem
:factorialreal
set /a counter=1
set /a result=0
:loop1
    set /a test=input+1
    if "%counter%"=="%test%" (
        goto end
    ) else (
        set /a result*=%counter%
    )
    set /a counter+=1
    goto loop1
:end1
goto aftercall

:factorial
if %input%==0 (
    set /a result=1
) else if %input%==1 (
    set /a result=1
) else if %input%==2 (
    set /a result=2
) else if %input%==3 (
    set /a result=6
) else if %input%==4 (
    set /a result=24
) else if %input%==5 (
    set /a result=120
) else if %input%==6 (
    set /a result=720
) else if %input%==7 (
    set /a result=5040
) else if %input%==8 (
    set /a result=40320
) else (
    set /a result=362880
)
goto aftercall
:main

rem  *we check all possible sums of factorials with reasonable digit
rem  *frequencies and see if these sums are the sums of the factorials
rem  *of their digits. This is really big and sloppy...but oh well,
rem  *and the brute-force method (check all numbers from 1 to an upperbound,
rem  *see if that number is the sum of the factorial of its digits) was
rem  *far too slow

set /a test=0
set /a answer=0
set /a c1=0
:loop-01
 set /a c2=0
  :loop-2
   set /a c3=0
    :loop-3
     set /a c4=0
      :loop-4
       set /a c5=0
        :loop-5
         set /a c6=0
          :loop-6
           set /a c7=0
            :loop-7             
             set /a c8=0
              :loop-8               
               set /a c9=0
                :loop-9
                 set /a test+=c1
                 set /a test+=c2*2
                 set /a test+=c3*6
                 set /a test+=c4*24
                 set /a test+=c5*120
                 set /a test+=c6*720
                 set /a test+=c7*5040
                 set /a test+=c8*40320
                 set /a test+=c9*362880
                 set /a j=test
                 set /a digifacsum=0
                 :testloop
                  if %digifacsum% GTR %test% (
                   goto endtest
                  )
                  if %j%==0 (
                   goto endtest
                  )
                  set /a input=j %% 10
                  set /a j/=10
                  goto factorial
                  :aftercall
                  set /a digifacsum+=result
                  goto testloop
                 :endtest
                 if %test% GTR 10 (
                  if %digifacsum%==%test% (
                     set /a answer+=test
                  )
                 )
                 set /a test=0
                 if not %c9%==0 (
                  set /a c9+=1
                  goto loop-9
                 )
                :end9
               if not %c8%==1 (
                set /a c8+=1
                goto loop-8
               )
              :end8
             if not %c7%==1 (
              set /a c7+=1
              goto loop-7
             )
            :end7
           if not %c6%==1 (
            set /a c6+=1
            goto loop-6
           )
          :end6
         if not %c5%==2 (
          set /a c5+=1
          goto loop-5
         )
        :end5
       if not %c4%==3 (
        set /a c4+=1
        goto loop-4
       )
      :end4
     if not %c3%==3 (
      set /a c3+=1
      goto loop-3
     )
    :end3
   if not %c2%==2 (
    set /a c2+=1
    goto loop-2
   )
  :end2
 if not %c1%==2 (
  set /a c1+=1
  goto loop-01
 )
:end01
echo %answer%

Problem 33 - Bash, for a change of pace

Recently, most of my solutions have been either in very nice or very esoteric languages. For this problem, I decided to use bash: certainly a very real language, just not exactly one that is normally used for the likes of Project Euler. Anyway, this problem went fairly well, even though I had to do something fairly silly to account for all variables storing integers (I only operation I perform once I have the value of a fraction is comparison...so I just multiply all fractions by 1000 to store them as integers) - and I was a bit of a wimp on the last step (finding the denominator of a simplified fraction in a way that only works when the numerator of the simplified fraction is 1, instead of a more generalized method) - but nonetheless, everything worked out well, and another language is crossed off my list of options. Notably, using bash reminded me that I still haven't used assembly language...
#!/bin/bash

RETURN=0
function div {
    let RETURN=$[1000*$1/$2 | bc -l]
}

ORIGINAL=0
NUMERATOR=1
DENOMINATOR=1
for i in `seq 10 99`;
do
    for j in `seq $[$i+1] 99`
    do
        div $i $j
        let ORIGINAL=$RETURN
        if [ $[j / 10] -eq $[$i % 10] ]; then
            if [ $[$j % 10] -gt 0 ]; then
                div $[$i / 10] $[$j % 10]
                if [ $ORIGINAL -eq $RETURN ]; then
                    let NUMERATOR*=$i
                    let DENOMINATOR*=$j
                fi
            fi
        fi
    done
done

#This is obviously not generally how one finds the denominator
#of a lowest-terms fraction...but it is in this case, as the
#numerator is a factor of the denominator
echo $[$DENOMINATOR / $NUMERATOR]

Thursday, August 29, 2013

Progress

Again, this table was no longer on the front page, and as it allows to see everything I have done at a glance, here it is again:
Here is a table which maps out which languages I used on which problems, complete with links to my code for each problem. The statement of the Nth problem can be accessed at projecteuler.net/problem=N . A * indicates a solution that has been replaced by a solution in another language or an analytic solution.

BrainFuck 1
Haskell 2*, 37
J 3*, 24*, 35
Ruby 4*, 30
Whenever 2, 5*
Ook! 6
Racket 7*, 26
K 8*
Javascript 9*, 31
sML 10*
PHP 11
Go 12*, 32
cLisp 13
C/C++ 14
Fortran95 3, 15*
Python 16*, 24
ELM 17
Scala 18
Perl 19
Java 20
FALSE 4
Squirrel 21
D 22
Ceylon 23
Postscript 7
Befunge 27
Boo 29
Frink 16
Forth 9
Shakespeare 12
Bash 33
Batch 34
Whitespace 36
LOLCODE 10
Analytic 5,8,15
Analytic 25, 28

Some nice, simple stuff - Problem 32 in Go.

After freeing up Go with my Shakespeare solution, I decided to solve another problem with it. This was just some nice simple programming, while getting to learn some more features of Go - I wouldn't mind getting another chance to use Go again. The problem was to find all numbers that are part of a 1-9 pandigital product (that is, a product P with X x Y = P such that the concatenation of the digits in X, Y, and P contains exactly the digits 1-9 occurring exactly once) - notably my upper bounds that I established are very rough and could be lowered, but nonetheless, this solution ran in about 1.5s on my computer.
package main

import "fmt"
import "sort"

func getDigits(x int) []int {
    d := []int{}
    for x > 0 {
        d = append(d, x % 10)
        x /= 10
    }
    return d
}

func pandigitalProduct(x int, y int) (bool, int) {
    prod   := x * y

    digits := []int{}
    digits  = append(digits, getDigits(x)...)
    digits  = append(digits, getDigits(y)...)
    digits  = append(digits, getDigits(prod)...)
    sort.Ints(digits)
    if len(digits) == 9 {
        for i, value := range digits {
            if value != i + 1 {
                return false, 0
            }
        }
        return true, prod
    }
    return false, 0
}
func contains(lst []int, x int) bool {
    for _, value := range lst {
        if value == x {
            return true
        }
    }
    return false
}
func main() {
    validProds := []int{}
    for i := 0; i < 10000; i += 1 {
        for j := i; j < 10000; j += 1 {
            isPandigital, product := pandigitalProduct(i, j)
            if isPandigital && !contains(validProds, product) {
                validProds = append(validProds, product)
            }
            if j * i > 100000 {
                break
            }
        }
    }
    sum := 0
    for _, num := range validProds {
        sum += num
    }
    fmt.Println(sum)
}

Spl Git Repository

For anyone who wants to get my Shakespeare compiler through a channel somewhat more normal/likely to work in the future than the dropbox link I put here earlier, I made a git repository for it (notably my first use of git, but I am 99% sure everything is there)
https://github.com/drsam94/Spl/

Wednesday, August 28, 2013

Return to Problem 12...In Shakespeare!

After spending about 5 days writing my Shakespeare compiler (Nota Bene: I did do other things on those days), I was pretty familiar with the language, and it didn't take terribly long to port my solution to Project Euler problem 12 from Go to Shakespeare. At first I was thinking I would port problem 10 (I used ML before, it asks for the sum of all primes below 2 million), but that seemed too easy as I spent most of today debugging my compiler's interaction with an example prime-sieve program. So, instead, I solved Problem 12, in which I had to find the first triangle number with over 500 divisors - and now I will get to use Go again, and Go was fun (in the easy way, not the way in which Shakespeare is fun). I quite like my solution - in runs quickly, it has plenty of Shakespearean characters, etc, etc - After writing a program in Shakespeare, I definitely agree with the suggestion someone gave me earlier that saying "let us return to scene X" in the dialog is kind of silly...I may add a feature that allows using descriptive scene names if I decide to go back to my compiler any time soon. This didn't take too long to write, other than multiple times when I forgot what data Juliet, Julia, Ophelia, etc were supposed to represent.

Anyway, the source code (for anyone interested, the compiled C code: https://dl.dropboxusercontent.com/u/34972177/PELC/e12.c):
The Tale of the 12th Euler.

Juliet, a young woman with a love for triangles.
Ophelia, another young woman who loves factors.
Octavia, a young woman who holds a big number.
Macbeth, a temporary young man who likes roots.
Romeo, a man who likes counting (and Juliet).
Julia, a young woman who also counts.

    Act I: Some smalltalk (not the Squeak kind)

    Scene I: Octavia's Initialization.

[Enter Juliet and Octavia]

Juliet:
    You cute beautiful amazing sweet sunny trustworthy gentle 
    golden good girl! You are as pretty as the difference between 
    thyself and the sum of a brave charming bold noble warrior and 
    the evil dirty devil!

Octavia:
 You are a pretty girl too, thanks much for the accolades.

[Exeunt]
[Enter Macbeth and Romeo]
  
    Act II: A non-trifling time

    Scene I: Getting to work

Macbeth:
    You are as cunning as the sum of thyself and a hero.

[Exit Macbeth]

[Enter Juliet]
Romeo:
    You are as lovely as the quotient of the product of myself 
    and the sum of myself and Heaven and a good King!

[Exit Juliet]

[Enter Macbeth]
Romeo:
    You are as prompt as the square root of Juliet!
[Exit Macbeth]

[Enter Ophelia]
  
    Scene II: Getting ready to factor.

Romeo: 
 You are nothing at all.

Ophelia: 
 Is the square of Macbeth as noble as Juliet?

Romeo: 
 If so, you are as beautiful as a flower.

[Exit Romeo]
[Enter Julia]

Ophelia: 
 You are an angel.


    Scene III: Time for real factoring.

Ophelia: 
 Is the remainder of the quotient between Juliet and thee better than nothing?
         
Julia:
 If not, you are as pretty as the sum of thyself and a golden flower.

Ophelia:
 You are as cute as the sum of yourself and a plum. 
 Art thou more pretty than Macbeth?

Julia:
 If so, let us proceed to Scene IV. If not, let us return to Scene III.

    Scene IV: The Final Judgment (or going back for more work).

[Exeunt]
[Enter Romeo and Ophelia]

Romeo:
 Are you more pretty than Octavia?

Ophelia:
 If so, let us proceed to Scene V.

[Exit Ophelia]
[Enter Macbeth]

Macbeth:
 Let us return to Scene I.

    Scene V: The Answer is Printed.

[Exeunt]
[Enter Juliet and Ophelia]

Ophelia: 
 Open Your Heart!

Juliet: 
 You are as beautiful as the product of a good man and the sum 
 of the lord and a cute golden girl. Speak Your Mind!

[Exeunt]

Shakespeare Compiler Done for Real

Turns out that it took another day to get my Shakespeare compiler from "can compile Hello World properly" to "can compile most Shakespeare programs correctly." My compiler still lacks support for stacks (because who needs data structures in shakespeare, really?), multiple-word nouns in cases where using just the last word would generate any confusion (right now I cheat on multiple word names and nouns by just counting the last word..."The Ghost" is just "Ghost, " etc.), and I don't restrict variable names, though it would go against the spirit of a Shakespeare program to not restrict oneself to Shakespearean variables. Also I don't support variable declarations that go across multiple lines, but that won't be too hard to add later.

The output has gotten a bit messier since yesterday...I had to forgo my distaste for goto statements and actually implementing them, as the issue with replacing gotos with function calls is the potential for stack overflow (which my Shakespeare program did indeed run into before I put all the gotos in). Anyway, I wrote this Shakespeare compiler mostly for my own purposes, but if anyone else wants to write Shakespeare and can't find a compiler that works on the internet, here is mine: splc.py is the source for the compiler, but because I use some fairly strange input syntax, I included a bash script (called spl) which automatically compiles to Shakespeare to C, and then from C to an executable with gcc. (Also, it is worth noting that the include directory, the python script, and the bash script need to all be in the same directory for things to work).

https://dl.dropboxusercontent.com/u/34972177/SPL/spl.zip

Tuesday, August 27, 2013

Shakespeare Compiler Written!

The last few days, I have been in Florida visiting my grandparents. With nothing better to do, I decided to finish up writing my compiler for the Shakespeare language. As of now, the compiler is good enough to correctly compile the example hello world program - I still have a couple of additional features to implement, most of which I will probably want when I actual solve a Project Euler problem in Shakespeare in the next couple days.

The missing features are:

  • Shakespeare is supposed to restrict variable names to names of real Shakespeare characters...I have yet to implement this restriction
  • Because of how I am currently treating any word delimited by spaces as a separate token, I have yet to implement support for multi-word names, nouns, and operators - this shouldn't be terribly hard to fix, but will be at least a little annoying...I didn't notice until the very end that multi-word names, nouns, and operators existed, but the example Primes.spl file from the Shakespeare website notably uses "The Ghost" as a variable and the "square root operator.
  • I have not implemented Stacks...notably these are only needed for turing completeness if I implement the naming restriction, so... (but anyway, these would be useful)
  • Any feature not used in the example hello.spl I have is untested, but "should" work (this includes gotos and input).
I won't publish my compiler until the above issues are taken care of, but, other than those issues, my compiler (written in python) correctly compiles Shakespeare code to C.
Below is the C output of my compiler for the Shakespeare program below it...it comes out a little bit less nice than the standard C hello world (nice indentation is pretty low on the priority list):
// hello.spl
#include < stdio .h >
#include "include/mathhelpers.h"
int condition = 0;
int Romeo = 2;
int Juliet = 2;
int Ophelia = 1;
int Hamlet = 1;
void act_1_scene1() {
Romeo = -64 ;
Romeo = (8 - Romeo) ;
fprintf(stdout, "%c", (char)Romeo);
Romeo = (-128 + 32) ;
Romeo = ((4 + 1) - Romeo) ;
fprintf(stdout, "%c", (char)Romeo);
Romeo = (Romeo + (8 - 1)) ;
fprintf(stdout, "%c", (char)Romeo);
fprintf(stdout, "%c", (char)Romeo);

 }
void act_1_scene2() {
Juliet = ((Romeo + 1) + 2) ;
fprintf(stdout, "%c", (char)Juliet);

 }
void act_1_scene3() {
Ophelia = (4 * 8) ;
fprintf(stdout, "%c", (char)Ophelia);
Ophelia = (8 * (1 + 2)) ;
Ophelia = (Juliet - Ophelia) ;
fprintf(stdout, "%c", (char)Ophelia);

 }
void act1() {
act_1_scene1();
act_1_scene2();
act_1_scene3();
}
void act_2_scene1() {
fprintf(stdout, "%c", (char)Juliet);
Juliet = (Juliet + (4 - 1)) ;
fprintf(stdout, "%c", (char)Juliet);
fprintf(stdout, "%c", (char)Romeo);
Romeo = Hamlet ;
Romeo = (square((2 - -4)) - cube(-4)) ;
fprintf(stdout, "%c", (char)Romeo);

 }
void act_2_scene2() {
Ophelia = (Romeo / (4 + -1)) ;
fprintf(stdout, "%c", (char)Ophelia);
Juliet = (Romeo / twice((1 - -4))) ;
fprintf(stdout, "%c", (char)Juliet);

 }
void act2() {
act_2_scene1();
act_2_scene2();
}
int main() {
act1();
act2();
}
The Infamous Hello World Program.

Romeo, a young man with a remarkable patience.
Juliet, a likewise young woman of remarkable grace.
Ophelia, a remarkable woman much in dispute with Hamlet.
Hamlet, the flatterer of Andersen Insulting A/S.


                    Act I: Hamlet's insults and flattery.

                    Scene I: The insulting of Romeo.

[Enter Hamlet and Romeo]

Hamlet:
 You lying stupid fatherless big smelly half-witted coward!
 You are as stupid as the difference between a handsome rich brave
 hero and thyself! Speak your mind!

 You are as brave as the sum of your fat little stuffed misused dusty
 old rotten codpiece and a beautiful fair warm peaceful sunny day. 
 You are as healthy as the difference between the sum of the
 sweetest reddest rose and my father and yourself! Speak your mind!

 You are as cowardly as the sum of yourself and the difference
 between a big mighty proud kingdom and a horse. Speak your mind.

 Speak your mind!

[Exit Romeo]

                    Scene II: The praising of Juliet.

[Enter Juliet]

Hamlet:
 Thou art as sweet as the sum of the sum of Romeo and his horse and his
 black cat! Speak thy mind!

[Exit Juliet]

                    Scene III: The praising of Ophelia.

[Enter Ophelia]

Hamlet:
 Thou art as lovely as the product of a large rural town and my amazing
 bottomless embroidered purse. Speak thy mind!

 Thou art as loving as the product of the bluest clearest sweetest sky
 and the sum of a squirrel and a white horse. Thou art as beautiful as
 the difference between Juliet and thyself. Speak thy mind!

[Exeunt Ophelia and Hamlet]


                    Act II: Behind Hamlet's back.

                    Scene I: Romeo and Juliet's conversation.

[Enter Romeo and Juliet]

Romeo:
 Speak your mind. You are as worried as the sum of yourself and the
 difference between my small smooth hamster and my nose. Speak your
 mind!

Juliet:
 Speak YOUR mind! You are as bad as Hamlet! You are as small as the
 difference between the square of the difference between my little pony
 and your big hairy hound and the cube of your sorry little
 codpiece. Speak your mind!

[Exit Romeo]

                    Scene II: Juliet and Ophelia's conversation.

[Enter Ophelia]

Juliet:
 Thou art as good as the quotient between Romeo and the sum of a small
 furry animal and a leech. Speak your mind!

Ophelia:
 Thou art as disgusting as the quotient between Romeo and twice the
 difference between a mistletoe and an oozing infected blister! Speak
 your mind!

[Exeunt]

Friday, August 23, 2013

Problem 31 - Javascript

I got a little bit of the Shakespeare compiler done today, but I decided to take a break and solve a problem in a comfortable language - the Shakespeare compiler doesn't seem too hard to write, the most annoying part will be working with all of the silly wordlists of "neutral adjectives," "bad adjectives," etc, etc.

Any, problem 31 - I remember this one giving me problems my first run through project Euler, but I am not entirely sure why, pretty simple solution - I decided to use Javascript in order to take it easy, but I would not be surprised if I resolve this with something far more ridiculous later.


amounts = new Array(1, 2, 5, 10, 20, 50, 100);
ways = 1; //accounts for the 2 pound coin

function helper(amountIndex, inheritedAmount) {
 for (var i = 0; i <= 200; ++i) {
  current = inheritedAmount + (i * amounts[amountIndex]);
  if (current > 200) {
   break;
  } else if (current == 200) {
   ways++;
   break;
  } else if (amountIndex < amounts.length - 1) {
   helper(amountIndex + 1, current);
  }
 }
}

function euler31() {
 helper(0,0); 
 alert(ways);
}

Thursday, August 22, 2013

Problem 9 redone in Forth

Another example of redoing a problem for which I used up a known language too early...this time I recovered Javascript by using Forth, which is a pretty old stack-based language. All the documentation I could find online was old and had everything in all-caps...so that apparently influenced my code:
: NUMS BEGIN DUP 1 - DUP 1 =  UNTIL ;
: NEWTON { t x } t x t / + 2 / DUP t ;
: SQRT { x } x 2 / BEGIN x NEWTON SWAP - 2 < UNTIL ;
: ISSQUARE { x } x SQRT DUP * x = ;
: CSQUARED { a b } a a * b b * + ;
: TEST { a b } a b CSQUARED ISSQUARE IF a b a b CSQUARED SQRT 
  + + 1000 = IF a b a b CSQUARED SQRT * * . CR bye THEN THEN ;
: INNERLOOP { a } 800 NUMS BEGIN DUP a TEST 800 = UNTIL ;
: OUTERLOOP 800 NUMS BEGIN INNERLOOP DUP 800 = UNTIL ;  
OUTERLOOP

Monday, August 19, 2013

Reading INTERCAL documentation

Today I got a lot of problems done...all in languages that were actually designed for humans. I am starting to read the documentation for INTERCAL, a pretty infamously horrendous language for programming in...hopefully I will get a solution done in that language by the end of the week.

The feature of INTERCAL that I so far find the most ridiculous - for code to be executed, it can be put in a DO command or a PLEASE DO command - the two are the same, but if you have too many more DOs than PLEASE DO's, than your program will get a compile-time error for being impolite, and if you have too many PLEASE DO's, than your program gets an error for being obnoxious / too polite.

Problem 30 - Re-using Ruby

I originally used Ruby on problem #4, and then recovered it...now I am using it for problem 30. Though I have not written a line of the language outside of Project Euler, I am starting to like it.
def sumDigiFifthPowers(x)
 ret = 0
 (1..(x.to_s.length)).each {|i|
 ret += ((x % (10 ** i)) / (10 ** (i - 1))) ** 5 }
 return ret
end

ans = 0
#upper bound is sumDigiFifthPowers(999999) as it is 5 digits
#nothing less than it can have the desired property
(100..354294).each {|num| 
 if num == sumDigiFifthPowers(num)
  ans += num
 end
} 
print ans

Problem 16 redo in Frink

My previous solution to problem 16 was in Python, but I would like to be able to use such a versatile language again in the future, so I decided to revisit the problem in Frink - this problem is trivial in any language that supports arbitrary-size integers, and Frink is such a language.
num = 2^1000
digisum = 0
while num > 0 
{
    digisum = digisum + (num % 10)
    num = num div 10
}
println[digisum]

Progress

The previous post of my progress is no longer visible on the front page, and as it is a fairly useful table that allows for access to all my code and seeing what has been done at a glance, I decided to repost it:
Here is a table which maps out which languages I used on which problems, complete with links to my code for each problem. The statement of the Nth problem can be accessed at projecteuler.net/problem=N . A * indicates a solution that has been replaced by a solution in another language or an analytic solution.

BrainFuck 1
Haskell 2*
J 3*,24
Ruby 4*, 30
Whenever 2, 5*
Ook! 6
Racket 7*, 26
K 8*
Javascript 9*, 31
sML 10
PHP 11
Go 12*, 32
cLisp 13
C/C++ 14
Fortran95 3, 15*
Python 16*
ELM 17
Scala 18
Perl 19
Java 20
FALSE 4
Squirrel 21
D 22
Ceylon 23
Postscript 7
Befunge 27
Boo 29
Frink 16
Forth 9
Shakespeare 12
Analytic 5,8,15
Analytic 25, 28

Problem 29 - Boo

After struggling with Befunge yesterday, I decided it was time for something a bit more reasonable - so I used Boo, a language based on Python with some additional features in order to take advantage of the "Common Language Infrastructure" - I didn't get a chance to use too many of these fancy features...the biggest difference from Python I got to encounter were some weird runtime errors that were fixed by using intermediate variables to store variables in order to spread computation across multiple lines.
def whatPower(x as int):
    for i in range(0, 8):
        n = 7 - i
        # Not using these intermediate variables
        # causes weird errors at runtime
        y as int = (x ** (1.0 / n)) cast int
        z as int = y ** n
        if z == x:
            return n
    return 1

def refine(lst, n as int):
    return i for i as int in lst if ((i > n*100) or (i % n > 0))

def validPows(n as int) as int:
    lst = i for i in range(2, (100 * n) + 1)
    for j in range(1, n):
        lst = refine(lst, j)
    lst2 = i for i in lst if (i % n == 0)
    ans = 0
    for i in lst2:
        ans += 1
    return ans
        
def contribution(x as int) as int:
    return validPows(whatPower(x))

ans as int = 0

for i in range(2, 101):
    c = contribution(i) cast int
    #debug print code
    #print("$i : $c")
    ans += c
print ans

Sunday, August 18, 2013

Problem 27, and Befunge, conquered

After solving many of the problems in the 20's with very little difficulty, I felt as though something was wrong...so when I saw that problem 27 would not be too hard to brute force with just a prime sieve and some simple calculations, I thought it was time to bring out one of the "big guns" in esoteric language land - Befunge. For the uninitiated, Befunge is a language which, to quote wikipedia, is "A worthy companion to INTERCAL, a computer language family which escapes the quotidian limitation of linear control flow and embraces program counters flying through multiple dimensions with exotic topologies." So, yeah - the basics of the language are that your programs are 2-dimensional instead of 1-dimensional, and control flow is directed with the operators >,<,^,v, |, and _. The first 4 direct the execution of your program in the indicated direction, and the other 2 change direction conditionally - down if the top element of the stack is 0, up otherwise, or left if nonzero, right otherwise. So yes, as indicated from those operators, this language is stack-based - which leads to some interesting interactions when code that has to be written backwards becomes easier to parse, on account of postfix notation becoming prefix notation - or maybe writing code in Befunge for 3 days has just made me go crazy, seeing as I can now read and write code that goes up, down, left, or right.

As though code that runs in whatever direction it feels like wasn't enough, Befunge has some other great little goodies that come with it - for one, there are no variables, but there is a method of data storage and retrieval - there is the 'p' command, which allows you to store an ascii character at a location in your source code, and the 'g' command, which allows you to access the ascii value of the character at a location in your source code...the syntax isn't too bad until you need variables with values over 256, which I then stored in two characters in base 256 notation. Storing a variable like this requires the following code:
pYY/***4444: pXX%***4444:<

where XX and YY are the locations where the variable is to be stored...note that the above code reads right to left...there was no place in my code where I performed this in a straight left to right line. Retrieval of the variable is then as simple as

XXgYYg4444****+

So with variable reading and writing so simple to perform, what could possibly go wrong?

Well, I often made mistakes accessing variables (is this variable stores at 0,1 or at 1,1 or...its hard to keep track, even though I did name the locations where I stored them to help a bit) Also, its very easy to misalign some arrows, and thus either enter an infinite loop or just do really funky unwanted stuff (the code is on the surface of a torus...if you go off one end, you loop around). Finally, debugging is very hard, as adding print statements requires reformatting of your code.

As though all this wasn't enough, in order to get my code to run in reasonable time, I needed a prime sieve that was at least a bit smarter than dividing by every single number from 2 to p-1...so, I wanted to divide up to sqrt(p). But, of course, Befunge doesn't have a square root function, so I had to implement my own version of Newton's method, and allocate some space in the lower-right hand corner of my code for it.

As a final aside - I ever so slightly broke my "the program must print the answer" rule for this one - in order to iterate over all candidate quadratic polynomials for this problem of the form n^2 + an + b, with |a| < 1000 and |b| < 1000, this program must be run twice, once for negative a, and once for positive a. However, once you know that the answer happens when a is negative, you can just run the negative version and get the answer every time...in about 45 seconds on my machine, despite the ridiculousness that is Befunge. My monstrous square of code is below (comments added for readers' sake, I did not include them originally) (Image below because I couldn't get the alignment right in the post...link to code in text form is here: https://dl.dropboxusercontent.com/u/34972177/PELC/e27comments.fun


Thursday, August 15, 2013

Problem 28 - more straight up math, no programming

I am approaching a solution for problem 27 in Befunge...I am not entirely sure how close I am though, because Befunge isn't exactly an easy language to debug. Anyway, while I was working through problem 27, I decided to look at problem 28. Again, this problem wound up being a lot easier to solve using math than with programming, so while I keep hacking away at Befunge, yet another problem has been crossed off the list without having to cross a language off the list. My solution goes like this:


It can be observed that if we number the rings with odd numbers n (1,3,5..), then (not counting the innermost ring), the numbers in the corner of the nth ring are:
(n - 2)^2 + (n - 1), (n - 2)^2 + 2*(n - 1), (n - 2)^2 + 3*(n - 1), (n - 2)^2 + 4*(n - 1)

taking the sum of these numbers and converting to a more reasonable index n (0,1,2,..) we get that the sum of the corners in the nth ring (for n > 0) is

4*(2(n-1) + 1)^2 + 20n

moving some terms around and adding in a 1 for the innermost ring, we get that the sum of the corners of the first 501 rings (and thus the sum of the diagonals of the 1001x1001 spiral) is

1 + 4*sum{from n = 1 to 500} (4n^2 + n + 1)

I am not sure if the recent problems have been more suited to pencil and paper solutions than earlier problems, or working with Befunge has just made me want to look for one more...but hopefully after Befunge is done, programming will become the norm again also. I feel like I am almost there with Befunge, but it is really hard to tell when debugging is impeded by the fact that you can only see printed out statements if the program successfully terminates, and also you have to deal with the fact that it might be near impossible to add a print statement in a certain place to debug because it would throw off the alignment of your code.

Wednesday, August 14, 2013

Problem 26 - Racket

So, I recently got Racket/Scheme back as a potential language after redoing the problem I first did in Racket in Postscript. I originally did my first 50 or so euler solutions in Racket, so I am pretty familiar with it - however, this time I was either tired or using this language that I haven't used for a while brought back old bad habits, so my solution, while working, is, I think, pretty sloppy (or at least the way I wrote it was pretty sloppy...constantly tweaking things in a mildly haphazard fashion until I got a correct solution). Anyway, this served as a brief interlude as I have begun working on Problem 27 and needed a break...I am writing that solution in Befunge, which is just a little crazy.
#lang racket

(define (index-of l x)
  (for/or ([y l] [i (in-naturals)] #:when (equal? x y)) i))

(define (biggest-cycle x)
  (define (helper prev lst)
    (let ([n (modulo (* 10 prev) x)])
      (if (zero? n) 0
        (if (and (member (* 10 prev) lst) (< x (* 10 prev))) 
            (- (length lst) (index-of lst (* 10 prev))) 
            (helper n (append lst (cons (* 10 prev) '())))))))
  (helper 1 '()))

(define (euler26)
  (define (f x max maxn)
    (let ([k (biggest-cycle x)])
      (if (= x 1000) maxn
          (if (> k max) (f (add1 x) k x) (f (add1 x) max maxn)))))
  (f 1 0 0))
        
(euler26)

Tuesday, August 13, 2013

Problem 25 - No code Necessary

Problem 25 asks for which fibonacci number is the first to contain 1000 digits: as a method for solving this by hand came to mind pretty quickly, I didn't find it necessary to write any code, as I could quickly write down a solution which I could feed into a calculator:
The nth fibonacci number can be expressed as fib(n) = (phi^n + (-phi)^-n / sqrt(5)), where phi=1.618... is the golden ratio.
As n is large, the second term in the sum is nearly 0, so we need only find the smallest integer n such that

phi^n / sqrt(5) > 10^999

Solving for n gives

n = ceil ( 999 * log_phi (10) + log_phi(sqrt(5)) )
So, now I have finished 25 problems and therefore reached "Level 1" on Project Euler. Maybe the next problem will require actually writing some code.

Design Change - inline code

As the most important feature of what I am recording here is my experiences writing code in various languages, it seems reasonable that I should include my code in blog posts directly, instead of just having links to a dropbox. So, all my older posts have been revised to have the code I wrote to solve the problem inline, with (limited) syntax highlighting. The syntax highlighting is now all based on Java...for obvious reasons it might be hard to get appropriate syntax highlighting for some of the languages that I am using, and as most languages are only going to be used once, it is unlikely to be worth hunting down the css to highlight it correctly.

I may go back and repost all my code from the original hackathon in the inline format, but for now just the code from after the hackathon is available in this way.

Monday, August 12, 2013

Problem 24 - J strikes again

Now that I freed up J, having previously wasted its power on problem #3, where the J solution involved 4 characters plus a number as input, I decided to use J for problem 24, where the solution is a whopping 6 characters, plus the input.

 999999 A.i.10 

Problem 7 Redo - Postscript

Problem 7 asks for the 10001st prime - making it one of the many, many Project Euler problems that require having a prime sieve. The first time through, I decided to use Racket to solve this problem because I had written prime sieves in Racket before, and I didn't really feel like writing a sieve in yet another language. However, now that I am continuing beyond problem 20, having Racket/Scheme around for future use will be helpful - so, I decided to redo this problem in a language which I have more experience writing an interpreters for (I have written 3) than I actually have experience writing code in - Postscript. Postscript is a stack based language, just like FALSE, except with more readable code and access to more functions (having access to sqrt, floor, ceiling, etc is nice), so even if postfix is a bit weird, this problem was a breeze compared to FALSE.

/isPrime
{
    
    /x exch def
    /more
    {
        dup 1 add x sqrt floor le
        {
            dup 1 add more
        } if
    } def
    1 more
    /retval true def
    /check
    {
        dup 1 eq not
        {
            x exch mod 0 eq
            {
                /retval false def
                %/poppin { dup 1 eq not { pop poppin } if } def
                %poppin
            }
            if
            check
        }
        { pop }ifelse
    }
    def check retval
} def

/counter 0 def
/current 2 def
/euler7
{
    current isPrime 
    {
        /counter 1 counter add def
    } if
    counter 10001 eq not
    {
        /current 1 current add def
        euler7
    } if
} def
euler7 current pstack

Problem 23 - Ceylon

Ceylon, a language based on Java, wasn't too hard to work with. It had some interesting features that made this fun, but compared to working with things like Brainfuck and FALSE, this was a very standard language. I will probably start working with more esoteric languages again soon.

void euler23() {
   
    Boolean isAbundant(Integer x) {
        if (x < 12) {
            return false;
        }
        variable Integer sum = 0;
        Integer ceiling(Float f) { 
            if (f > f.integer.float) {
                return f.integer + 1;
            } else {
                return f.integer;
            } 
        }
        Integer root = ceiling(x.float^0.5);
        if (root * root == x) {
            sum += root;
        }
        for (i in 2..(root -1)) {
            if (x % i == 0) {
                sum += i + (x / i);
            }
        }
        return sum + 1 > x;
    } 
    Integer[] abundants = [for(i in 1..28123) if(isAbundant(i)) i];
    variable Integer ans = 0;
    for (i in 1..28123) {
        variable Boolean wasSum = false;
        for (a in abundants) {
            if (a >= i) {
                break;
            } else if(isAbundant(i - a)) {
                wasSum = true;
                break;
            }
        }
        if (!wasSum) {
            ans += i;
        }
    }
    print(ans);
}

Sunday, August 11, 2013

Problem 22 - D

Another problem solved with a language chosen off of the list of language used by other PE users, another language that has very C-like syntax, although D was a little more exciting to work with than Squirrel. The biggest problem I had with this one was a mistake in my find/replace to reformat the text file (My program assumes one name per line, no quotes or commas).

import std.stdio;
import std.conv;

void main() {
    string[] arr;
    auto sum = 0;
    foreach (line; stdin.byLine()) {
        arr ~= to!string(line);
    }
    arr.sort;
    foreach (i, name; arr) {
        auto wordval = 0;
        foreach (c; name) {
            wordval += to!int(c) - to!int('A') + 1;
        }
        sum += wordval * (i + 1);
    }
    writeln(sum);
}

Problem 21 - Squirrel

For my first new problem since the hackathon (problem 21), I decided to try Squirrel - I saw it on the list of languages that real people used to solve Project Euler problems, and the name sounded cool, so I thought it was worth a try. Turns out, its syntax is basically half C-like, half Python-like, so it was not hard to use at all. Anyway, I solved the problem.


Now, before I start doing any more, I need to change the formatting of my progress table, it is already overflowing the bounds of this blog. My Solution:
function sumOfDivisors(x)
{
    local sum = 0;
    if (x == (sqrt(x).tointeger()*sqrt(x).tointeger())) {
        sum += sqrt(x).tointeger(); 
    }
    for (local i = 2; i < sqrt(x); i +=1) {
        if (x % i == 0) {
            sum += i + (x / i);
        }
    }
    //only proper divisors - we do not count the number itself
    return sum + 1;
} 

local sum = 0;
for (local i = 3; i < 10000; i +=1) {
    local j = sumOfDivisors(i);
    if (i != j && sumOfDivisors(j) == i) {
        sum += i;
        print(i + ", " + j + "\n");
    }
}
::print(sum.tostring() + "\n");

Problem 4 - FALSE

I used Ruby on problem 4 before - it seemed like a good idea at the time, because I did not know any Ruby, other than the fact that I knew it had nice string functions, so testing for being a palindrome was as simple as x.to_s = x.to_s.reverse. However, Ruby is a "real" language that can actually do a lot of things, so I decided to revisit problem 4 with a ...different language.

FALSE was developed in 1993 with obfuscation and minimalism in mind - it is the language that inspired the development of brainfuck. Luckily, however, FALSE was not as bad as brainfuck, its a stack-based language, kind of like Postscript, except it takes the J-like approach to naming functions, so everything is done with crazy characters. Luckily, I didn't have to use the two characters in the language which are not on my keyboard, ß and ø . If I had needed to use those, writing the code would have been just a bit harder.

For this problem, the main difficulty came in actually running an interpreter - I could only find two interpreters on the language's homepage http://strlen.com/false-language. One was for 68000 assembly, and the other was for MS-DOS. So, I ran the dos interpreter on my computer through dosbox, which caused some complications, but worked out fine in the end. I got the answer, even if it took a while (the whole having to run the code in an emulator bit hurts), and I have used yet another esoteric language to clean up my early problems...maybe soon I will go forth and solve problems 21-25.

My Solution:
100a:100b:0q:[1000a;>][[1000b;>][a;b;*c:0d:0e:[5a;b;*100000>[1+]?e;>][
c;c;10/10*_+d;10*+d:c;10/c:e;1+e:]#a;b;*c:c;d;=c;q;>&[c;q:]?
1b;+b:]#a;b:a;1+a:]#q;.

Return to Problem 3 with Fortran

During the original challenge, I used the J language on Problem 3 - J was a good language for problem 3, because the solution took 4 characters to write...but J is a good language for many Project Euler problems, so it was silly to use it so early. During the challenge, I didn't really get to use Fortran...it ended up finding an analytic solution, so the Fortran code I wrote was reduced to being nothing more than a multiplication. So, I decided to revisit problem 3, using Fortran this time. Now that I have gotten used to it to a certain extent, Fortran isn't the worst programming language (hey, its better than Whenever which I used yesterday), and my solution did indeed run more quickly than I expected it to (~6ms, even though I wasn't exactly doing the most efficient prime factoring in the world)

!Program 
program euler
implicit none
integer :: N, ans
N = 600851475143
ans = 0
call bigpfac(N, ans)
print *, ans
end program euler

subroutine isprime(x, output)
implicit none
integer :: i, x, output
output = 1

do i=2, int(sqrt(real(x)))
if (mod(x,i) == 0) then
    output = 0
exit
end if
end do
end subroutine isprime

subroutine bigpfac(x, output)
implicit none
integer :: i, x, output, p
output = 0
do i=3,x,2
    call isprime(i, p)
    if (x == 1) then
        exit
    end if
    if ((p == 1) .and. (mod(x,i) == 0)) then
        output = i
        x = x / i
    end if
end do
end subroutine bigpfac
 


Saturday, August 10, 2013

First use of Swap Rule - "Whenever"

In the hackathon, I used the Whenever programming language trivially when I had an analytic solution just to perform a multiplication. But I decided to now go back and use it for real. The Whenever Programming Language (http://www.dangermouse.net/esoteric/whenever.html) executes lines of code in your program in whatever order it pleases - and it notably has no variables for state, the only state is the "wish-list" of lines of code to be executed randomly. My solution notably took 13 minutes for me to run, which is above the Project Euler limit...but I think I will let this slide, seeing as the runtime of a Whenver program is very nondeterministic: if I got lucky, I am pretty sure my program could run in a few milliseconds.

1 defer (9 || N(6) < 4000000) -2#N(2),-3#N(3),-4#N(4),-5#N(5),-6#N(6),-7#N(7),-8#N(8);
2 defer (7 || N(6) > 4000000 || N(8)>2 || N(3)>N(2)) 3#N(2),2,8;
3 defer (7 || N(6) > 4000000 || N(8)>2 || N(2)>N(3)) 2#N(3),3,8;
4 defer (9 || N(8)<3 || N(3)>N(2)) 6#N(3),-8#3,4,9;
5 defer (9 || N(8)<3 || N(2)>N(3)) 6#N(2),-8#3,5,9;
6 defer (1 > 0) 6;
7 2,8;
8 defer (1 > 0) 8;
9 print(N(6) - 1);

Progress

Here is a table which maps out which languages I used on which problems, complete with links to my code for each problem. The text of the Nth problem can be accessed at projecteuler.net/problem=N . A * indicates a solution that has been replaced by a solution in another language or an analytic solution.

BrainFuck 1
Haskell 2*
J 3*,24
Ruby 4*
Whenever 2, 5*
Ook! 6
Racket 7*, 26
K 8*
Javascript 9
sML 10
PHP 11
Go 12
cLisp 13
C++ 14
Fortran95 3, 15*
Python 16
ELM 17
Scala 18
Perl 19
Java 20
FALSE 4
Squirrel 21
D 22
Ceylon 23
Postscript 7
Befunge 27
Boo 29
Analytic 5,8,15, 25, 28

Introduction

For almost 24 hours over a 30 hour period (I did eat and sleep), I participated in the 4th Machinis Ludo Game Jam at the graphics lab at Williams College, which in this iteration was a generalized hackathon. As my challenge for this hackathon, I decided to try to solve 20 Project Euler problems in 24 hours ... in 20 different programming languages. This ended up being a very challenging and fun exercise, as well as one that was perfectly scoped (I finished with only 4 minutes to spare).

Project Euler has a set of increasingly difficult "math" problems that are meant to be solved through code. I have done about 100 of them without constraints (I used it as a way to learn Python and Racket/Scheme, as well as just to have fun), but now I am going through, trying to use each programming language only once. Now I have done 20 problems in 20 languages, but my goal is to eventually do 30 in 30, 40 in 40, etc...

The timed version of this challenge was fun and exiting for various reasons - I got to use esoteric programming languages with a "real" purpose in mind (this was probably the only way I was going to ever write 100 lines of BrainFuck in my life), I got to begin to learn real programming languages that I had never used before at least in a rudimentary manner (I got to use Ruby, Perl, Haskell, Go, and other languages for the first time), and I got to deal with some really interesting optimality problems - such as I have 2 hours left, 6 problems left, and only 4 languages left that I actually know how to use...how do I distribute languages to the problems, etc?

Now, I am going to embark on an untimed continuation of this challenge...I will try to do as many problems in as many languages as possible. The original rules I set for myself are here, but below are my revised/amended rules for this longer version:

Restatement of old Rules:

  • For two languages to be considered "different", they must not differ only in age or by a superset/subset relation. For example, Java 1, Java 2, and Java 7 are all one language to me, and as C++ is just a superset of C, C/C++ will count as one language. The only exceptions I may make to this rule are extreme subsets - for example, C++ with only templates and the C preprocesser.
  • All solutions must output the actual solution to the problem, not just intermediary data, and all solutions will be posted both here and, if I deem it interesting enough, to the Project Euler forums. It is worth noting that it goes against Project Euler policy to spread the answers outside of Project Euler, as everyone should do the work themselves. But I feel like the point of Project Euler is to work for the solutions, so the amount of interest there may be in my code in crazy languages probably outweighs any facilitation of "cheating" on Project Euler, because why would you cheat?
  • All solutions will be written independent of Project Euler-specific help on the problems (no looking at my old code from pre-PELC solutions, etc)
New Rules:
  • "The Swap Rule": When I was timing myself, once I used a solution for a problem, that was it, that language was shut off from me and I could not use it every again, its my own fault for using J to solve problem 3 (really, that was a dumb decision...J is pretty much the best PE language, at least for problems 1-50 or so). But now I am coming to a difficult point if I continued in this manner - I want to write more solutions, and I want to use crazy languages, but the problems are getting harder, so it is very hard to use a crazy esoteric language! So, I am adding the "Swap Rule", which is that if I can rewrite my solution to an earlier problem in a different language, I can swap the two solutions, allowing me to use the older language for another problem in the future.
  • "The Analytic Solution Rule": For a few problems (you know who I am talking about...Problems 5, 8, and 15), I could easily write down a solution in the form of a few multiplications, making writing a solution in code trivial...most languages support multiplication without jumping through many hurdles. Because using a hard language in this uncreative way is unfun (I used Whenever and Fortran95 on these...but I should use those for real things), If I can analytically (that is, with pencil, paper, my brain, a few minutes, and MAYBE a four-function calculator) I can find a solution, then no program need be written for that problem, so I don't waste any language solving that problem trivially. This way, whenever I use a language, I have to USE the language.\
With these two extra rules, I am ready to proceed in my challenge...most likely I will first "clean up" my initial 20 solutions using my new 2 rules, and then proceed into the great unknown that waits beyond question 21.