blog
http://samskivert.com/blog/
Recent content on blogHugo -- gohugo.ioen-usWed, 13 Jun 2018 00:00:00 +0000Ramblings on programming language design
http://samskivert.com/blog/2018/06/lang-design-rambling/
Wed, 13 Jun 2018 00:00:00 +0000http://samskivert.com/blog/2018/06/lang-design-rambling/Mario asked me an interesting question the other day. As is often my tendency, I gave him a multi-thousand word answer. Then he foolishly asked more interesting questions, so I hit him with additional walls of text. Be careful what you ask for kids. In the end, we figured we'd share with the class because perhaps some useful explanations happened along the way.
[Note: because I'm lazy I did not edit out all the profanity.Gradle Difficulties
http://samskivert.com/blog/2015/03/gradle-difficutles/
Tue, 17 Mar 2015 00:00:00 +0000http://samskivert.com/blog/2015/03/gradle-difficutles/When I first started doing Android stuff in earnest, I kept a list of Things That Sucked™ about Android, but I never cleaned it up and published it. Now (years later) I've forgotten the details of many of my infuriated scribblings, so I'm unlikely to ever publish it as I'd likely be complaining about things that have long since been fixed and end up misleading anyone who happened upon my rantings.Anne the Van
http://samskivert.com/blog/2014/04/anne-the-van/
Mon, 21 Apr 2014 00:00:00 +0000http://samskivert.com/blog/2014/04/anne-the-van/After fourteen long and glorious years of driver automobile partnership, Anne the Van and I are parting ways. Natalie has finally decided that it might be useful to drive, but she's not ready to drive something as majestic as Anne, so we're getting a smaller car.
Before turning her loose on the open market, I am putting out feelers to see if anyone "in the family" is in the market for the Fahrvergnügen experience.Thinking out loud about RSP
http://samskivert.com/blog/2013/11/thinking-aloud-rsp/
Thu, 07 Nov 2013 00:00:00 +0000http://samskivert.com/blog/2013/11/thinking-aloud-rsp/For a combination of reasons, I've finally gone completely mad and decided to try my hand at the Quixotic task of developing a new programming model. Naturally it will solve all of our problems and make delicious toast.
This is somewhat inspired by Bret Victor's excellent presentations, but is also something that has been gnawing at the back of my mind for some time. I even went so far as to spend a year in the PhD program with the PLSE group at UW before realizing that my preferred approach to tackling these problems doesn't fit well with that of CS academia.F# Cheat Sheet
http://samskivert.com/blog/2013/05/fsharp-cheat-sheet/
Wed, 08 May 2013 00:00:00 +0000http://samskivert.com/blog/2013/05/fsharp-cheat-sheet/I was looking for a good F# cheat sheet and found a nice one originally published by a6systems, which has since disappeared from the Internet.
I wasted thirty minutes of my life trying to track down a copy of the PDF. I found half a dozen sites that linked to the defunct original website, and a quarter dozen "document hosting" sites that insisted I register with them to download the damned thing.Spellwood Post-mortem
http://samskivert.com/blog/2013/03/spellwood-postmortem/
Fri, 01 Mar 2013 00:00:00 +0000http://samskivert.com/blog/2013/03/spellwood-postmortem/The fruits of the last year and change of my, Sean Keeton's, and a few other Dread Ringers' labor finally made its way to the App Store and Google Play last December. Now three months have gone by while I too infrequently found time to work on this post-mortem. I'm forcing myself to wrap it up today, lest the game be long forgotten by everyone but its author before this post-mortem is published.Aloha Aloha!
http://samskivert.com/blog/2013/02/aloha-aloha/
Tue, 05 Feb 2013 00:00:00 +0000http://samskivert.com/blog/2013/02/aloha-aloha/We finally moved into our new house on Aloha after many months of remodeling. It's not completely finished, but it's done enough that we're moving in and enjoying the company of the contractors for a few weeks.
I've posted some photos on the Googley Plus.Everthing but the kitchen async
http://samskivert.com/blog/2012/08/async-java/
Tue, 07 Aug 2012 00:00:00 +0000http://samskivert.com/blog/2012/08/async-java/I frequently suffer from Java's complete lack of assistance when it comes to asynchronous programming, but this little multi-phase maneuver really brings home the pain:
protected void findFriends (final Socks.Network sock, Group contents) { contents.removeAll(); final Label status = UI.wrapLabel(_msgs.findingFriends); contents.add(status); class FriendFinder { public void start () { // make sure we've authenticated with this network sock.authenticate(new Callback<Socks.Member>() { public void onSuccess (Socks.Member self) { gotSelf(self); } public void onFailure (Throwable err) { fail(_msgs.Stars (and brackets) on thars
http://samskivert.com/blog/2012/02/stars-and-brackets-on-thars/
Thu, 09 Feb 2012 00:00:00 +0000http://samskivert.com/blog/2012/02/stars-and-brackets-on-thars/One of my colleagues recently committed a change with the comment:
Log Message: ----------- Switching from "type *varname" to "type* varname" It gave me hope for the future, that we might overcome the legacy of K&R's terrible mistake when they pioneered the styles foo *pointer and foo array[].
The world has mostly come around to the view that [] is part of the type, not the variable (i.e. foo[] is how you declare 'array of foo').Happy New Year to Me!
http://samskivert.com/blog/2012/01/happy-new-year-to-me/
Tue, 03 Jan 2012 00:00:00 +0000http://samskivert.com/blog/2012/01/happy-new-year-to-me/I logged into the server that hosts samskivert.com yesterday and noticed that someone had done a very ham fisted job of hacking into my server (in addition to whatever nefarious business they hacked in to perpetrate, they changed the uid of my primary account to 0 and left the passwd file thusly modified). That's what I get for having anything other than Apache and sshd running.
Naturally, the only thing to do in such a case was to take off and nuke the site from orbit.“Fun with edge cases” or “Why your spec can never possibly be complete”
http://samskivert.com/blog/2011/08/fun-with-edge-cases-or-why-your-spec-can-never-possibly-be-complete/
Fri, 12 Aug 2011 00:00:00 +0000http://samskivert.com/blog/2011/08/fun-with-edge-cases-or-why-your-spec-can-never-possibly-be-complete/(Apologies for the duplication with Google+, still sorting out my syndication process.)
What do you think should happen if you do the following in Java?
Map<String,String> map = new HashMap<String,String>(); map.put("foo", "bar"); Iterator<Map.Entry<String,String>> iter = map.entrySet().iterator(); Map.Entry<String,String> entry = iter.next(); iter.remove(); entry.setValue("baz"); Should the entry freak out because you tried to update the mapping after it has already been removed? Should it reintroduce a mapping from “foo” to “baz”? Should the call succeed but have no effect on the map?Forecast: cloudy
http://samskivert.com/blog/2011/06/forecast-cloudy/
Sat, 04 Jun 2011 00:00:00 +0000http://samskivert.com/blog/2011/06/forecast-cloudy/Far too often, Google App Engine reports that everything is smooth sailing:
when the view from my app looks substantially less rosy:
My app is not complex. It stuffs data into the app engine data store and pulls it back out again. The total size of all my entities is one meeeellion bytes. The code is not massive; it’s seven jar files, the largest of which is the app engine API.Too much Maven Kool-aid
http://samskivert.com/blog/2011/06/too-much-maven-kool-aid/
Thu, 02 Jun 2011 00:00:00 +0000http://samskivert.com/blog/2011/06/too-much-maven-kool-aid/A post on the Sonatype blog cheerfully reports:
Adding an additional source folder is as simple as:
<project> ... <build> <plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>build-helper-maven-plugin</artifactId> <version>1.1</version> <executions> <execution> <id>add-source</id> <phase>generate-sources</phase> <goals> <goal>add-source</goal> </goals> <configuration> <sources> <source>some directory</source> ... </sources> </configuration> </execution> </executions> </plugin> </plugins> </build> </project> If that’s simple, I don’t want to see complicated.How I Learned to Stop Worrying and Love (Coding on) the Mac OS
http://samskivert.com/blog/2011/05/how-i-learned-to-stop-worrying-and-love-coding-on-the-mac-os/
Tue, 24 May 2011 00:00:00 +0000http://samskivert.com/blog/2011/05/how-i-learned-to-stop-worrying-and-love-coding-on-the-mac-os/I’ve been using Linux and X Windows as my primary operating system for development for a long time. Owing to the spotty or non-existent support of consumer applications over the years, I have generally maintained an auxiliary machine (sometimes Windows, sometimes a Mac) on which to run things like iTunes or the Flash Authoring Tool (or even the Flash player when Linux support was crap).
My primary machine has generally been a Mac, because I like the hardware, I just haven’t ever run Mac OS on it.Euler 66
http://samskivert.com/blog/2011/01/euler-66/
Fri, 14 Jan 2011 00:00:00 +0000http://samskivert.com/blog/2011/01/euler-66/Problem 066: (source):
import scala.collection.mutable.{Map => MMap} object Euler066 extends EulerApp { def leastx (d :Int) = { val amap = MMap[Int,BigInt]() val pmap = MMap[Int,BigInt]() val qmap = MMap[Int,BigInt]() val ppmap = MMap[Int,BigInt]() val qqmap = MMap[Int,BigInt]() def a (i :Int) :BigInt = amap.getOrElseUpdate(i, i match { case 0 => math.sqrt(d).toInt case _ => (a(0) + pp(i))/qq(i) }) def p (i :Int) :BigInt = pmap.getOrElseUpdate(i, i match { case 0 => a(0) case 1 => a(0)*a(1) + 1 case _ => a(i)*p(i-1) + p(i-2) }) def q (i :Int) :BigInt = qmap.Euler 65
http://samskivert.com/blog/2011/01/euler-65/
Thu, 13 Jan 2011 00:00:00 +0000http://samskivert.com/blog/2011/01/euler-65/Problem 065: (source):
object Euler065 extends EulerApp { case class Frac (numer :BigInt, denom :BigInt) { def + (n :BigInt) = Frac(n * denom + numer, denom) def invert = Frac(denom, numer) } def compute (count :Int, n :Int) :Frac = { val term = if (n == 1) 2 else if (n % 3 == 0) 2*(n/3) else 1 if (n == count) Frac(term, 1) else compute(count, n+1).invert + term } def answer = compute(100, 1).The eternal quest for personal information management nirvanaz
http://samskivert.com/blog/2010/11/the-eternal-quest-for-personal-information-management-nirvana/
Sun, 28 Nov 2010 00:00:00 +0000http://samskivert.com/blog/2010/11/the-eternal-quest-for-personal-information-management-nirvana/I have progressed through a broad variety of personal information management tools over the course of my life, and they invariably fail to meet my needs in one way or another. This periodically motivates a flurry of note taking on what would comprise the “perfect” personal information management system, which I generally record using whatever duct tape and baling wire contraption I am currently using to keep track of things, and then promptly forget about.WTFF?
http://samskivert.com/blog/2010/09/wtff/
Tue, 14 Sep 2010 00:00:00 +0000http://samskivert.com/blog/2010/09/wtff/I saw some weird background activity on my network interface and undertook an investigation. netstat readily revealed that Firefox had a metric ton of TCP connections open:
yonami.local:58809 cdce.sef004.interna:www ESTABLISHED 7215/firefox-bin yonami.local:58828 cdce.sef004.interna:www ESTABLISHED 7215/firefox-bin yonami.local:33425 pv-in-f106.1e100.ne:www ESTABLISHED 7215/firefox-bin yonami.local:58829 cdce.sef004.interna:www ESTABLISHED 7215/firefox-bin yonami.local:46025 208.50.77.78:www ESTABLISHED 7215/firefox-bin yonami.local:46001 208.50.77.78:www ESTABLISHED 7215/firefox-bin yonami.local:41860 208.50.77.95:www ESTABLISHED 7215/firefox-bin yonami.local:45853 pv-in-f100.1e100.ne:www ESTABLISHED 7215/firefox-bin yonami.local:45339 px-in-f102.1e100.ne:www ESTABLISHED 7215/firefox-bin yonami.local:58807 cdce.sef004.interna:www ESTABLISHED 7215/firefox-bin yonami.local:58801 cdce.sef004.interna:www ESTABLISHED 7215/firefox-bin yonami.Better symlink behavior for Git and Mercurial
http://samskivert.com/blog/2010/09/better-symlink-behavior-for-git-and-mercurial/
Fri, 10 Sep 2010 00:00:00 +0000http://samskivert.com/blog/2010/09/better-symlink-behavior-for-git-and-mercurial/Like most developers, you probably don't like unnecessary typing. By that, I don't mean the static and dynamic variety, but the fingers on keyboard variety. However, when it comes to manipulating files via version control, we have recently taken a step backward.
Historically, when faced with paths that look like the following:
src/main/java/com/company/project/foopkg/MyAwesomeFoo.java src/main/java/com/company/project/barpkg/MyAwesomeBar.java src/main/java/com/company/project/bazpkg/MyAwesomeBaz.java src/test/java/com/company/project/foopkg/MyAwesomeFooTest.java I have created symlinks at the top-level of my project as follows:
% ln -s src/main/java/com/company/project code % ln -s src/test/java/com/company/project tcode This allows me to do things like:Why Maven Sucks: Act I, Reprise
http://samskivert.com/blog/2010/09/why-maven-sucks-act-i-reprise/
Fri, 10 Sep 2010 00:00:00 +0000http://samskivert.com/blog/2010/09/why-maven-sucks-act-i-reprise/The XML insanity of passing compiler arguments to Maven like so:
<compilerArguments> <Xlint/> <Xlint:-serial/> <Xlint:-path/> </compilerArguments> has not surprisingly, come back to bite me in the ass. Most normal Maven actions seem to have no problem with it, but when I try to actually publish my project (via mvn release:prepare), I get the error I expected to see all along:
[INFO] ------------------------------------------------------------------------ [ERROR] BUILD ERROR [INFO] ------------------------------------------------------------------------ [INFO] Error reading POM: Error on line 104: The prefix "Xlint" for element "Xlint:-serial" is not bound.Why Maven Sucks: Halftime Show
http://samskivert.com/blog/2010/09/why-maven-sucks-halftime-show/
Thu, 09 Sep 2010 00:00:00 +0000http://samskivert.com/blog/2010/09/why-maven-sucks-halftime-show/One can, and is indeed encouraged to, sign one's Maven artifacts with GPG. This involves generating an artifact-version.jar.asc file containing the ASCII representation of the cryptographic signature for the artifact in question. This is uploaded to the Maven repository along with the artifact.
Maven then helpfully generates artifact-version.jar.asc.md5 and artifact-version.jar.asc.sha1, and uploads those to the repository as well. I don't need one, let alone two, cryptographic hashes to tell me that my cryptographic signature has not been tampered with.Why Maven Sucks: Act I
http://samskivert.com/blog/2010/09/why-maven-sucks-act-i/
Wed, 08 Sep 2010 00:00:00 +0000http://samskivert.com/blog/2010/09/why-maven-sucks-act-i/These ruminations were languishing in commit messages, which would normally satisfy my urge to complain. But now I need to complain further, and don't have a commit message in which to express my discontent, so I'm airing the whole basket of dirty laundry here, and going on the record as a Maven hater. For those of you privy to the original commit messages, my new complaints will be aired in Act III.Why Maven Sucks: Act II
http://samskivert.com/blog/2010/09/why-maven-sucks-act-ii/
Wed, 08 Sep 2010 00:00:00 +0000http://samskivert.com/blog/2010/09/why-maven-sucks-act-ii/Sun, in their infinite wisdom, circa Java 1.3, extended the jar file specification to allow dependencies to be expressed inside jar files by adding a Class-Path attribute to the MANIFEST.MF file. This causes the JVM (and javac, and various app servers) to try to magically add dependent jar files to the classpath. This is half-assed and wrong in too many ways to enumerate here.
Some other enthusiastic Sun engineer then helpfully added activation.Why Maven Sucks: Act III
http://samskivert.com/blog/2010/09/why-maven-sucks-act-iii/
Wed, 08 Sep 2010 00:00:00 +0000http://samskivert.com/blog/2010/09/why-maven-sucks-act-iii/The saga (act i, act ii) continues.
More reasons why Maven sucks:
Plugin version handling sucks. I learned this when I was trying to get Maven to generate javadocs. I was configuring the Maven Javadoc plugin with links to external javadocs when I discovered the very handy detectJavaApiLink option. It automatically adds a link to the standard Java API javadocs whose version matches the version specified in the -source argument to your compilation.Euler 2⁶
http://samskivert.com/blog/2010/08/euler-2%e2%81%b6/
Wed, 25 Aug 2010 00:00:00 +0000http://samskivert.com/blog/2010/08/euler-2%e2%81%b6/Problem 064: (source):
object Euler064 extends EulerApp { case class Root (root :Int, add :Int, div :Int) { def expand = { val term = ((math.sqrt(root) + add)/div).toInt val nadd = term*div - add (term, Root(root, nadd, (root - nadd*nadd)/div)) } override def toString = "(√" + root + "+" + add + ")/" + div } def expansion (terms :List[Int], roots :List[Root]) :List[Int] = { val (term, root) = roots.Shoot me now
http://samskivert.com/blog/2010/08/shoot-me-now/
Wed, 25 Aug 2010 00:00:00 +0000http://samskivert.com/blog/2010/08/shoot-me-now/I'm foolishly trying to write a javac annotation processor in Scala. This has already been a road fraught with gratuitous obstacles, but the latest wrinkle has driven me to vent in public.
When I run my annotation processor thusly:
javac -processor FooProcessor -processorpath fooproc/classes:blah/scala-library.jar SomeFile.java I get java.lang.IllegalStateException: zip file closed when my processor tries to load Scala classes. But if I unpack scala-library.jar into fooproc/classes then it works. Joy!Euler 62
http://samskivert.com/blog/2010/08/euler-62/
Sat, 21 Aug 2010 00:00:00 +0000http://samskivert.com/blog/2010/08/euler-62/Problem 062: (source):
object Euler062 extends EulerApp { def search (n :Long, cubes :Map[Long,List[Long]]) :Long = { val cube = n*n*n val key = cube.toString.sortWith(_>_).toLong val perms = cube :: cubes.getOrElse(key, Nil) if (perms.length == 5) perms.last else search(n+1, cubes + (key -> perms)) } def answer = search(1, Map()) } I was originally using the dreaded mutation here, and then realized that I could easily rewrite the code to use an immutable map, making it about 10% shorter and about 10% slower.Euler 63
http://samskivert.com/blog/2010/08/euler-63/
Sat, 21 Aug 2010 00:00:00 +0000http://samskivert.com/blog/2010/08/euler-63/Problem 063: (source):
object Euler063 extends EulerApp { def pows (n :Int) = Stream.from(1) prefixLength(p => BigInt(n).pow(p).toString.length == p) def answer = 1 to 9 map(pows) sum } The main observation here is that the number of digits of ax, for a ≥ 10, is guaranteed to exceed x. So we can restrict ourselves to looking only at the numbers from 1 to 9. Furthermore, the number of digits of ax, for 1 ≤ a ≤ 9, will equal x up to some maximum x, and then be less than x for all higher x.An emacs on every desktop
http://samskivert.com/blog/2010/08/an-emacs-on-every-desktop/
Thu, 12 Aug 2010 00:00:00 +0000http://samskivert.com/blog/2010/08/an-emacs-on-every-desktop/I am a heavy user of virtual desktops. I generally have a couple of shell windows, an emacs window, possibly a browser, and whatever target program I'm working on, on each of a few virtual desktops. When I'm interrupted from one project, I flip to the next virtual desktop, open a shell window, open an emacs window and start hacking away on said interruption. Often the stack will get three or four virtual desktops deep, and I'll find myself flipping back and forth between the various in-progress projects.Euler 58
http://samskivert.com/blog/2010/07/euler-58/
Tue, 27 Jul 2010 00:00:00 +0000http://samskivert.com/blog/2010/07/euler-58/Problem 058:
object Euler58 extends EulerApp { def checkring (r :Int, primes :Int, nums :Int) :Int = { if (primes*10/nums < 1) 2*r-1 else { val skip = 2*r val base = (skip-1)*(skip-1) val rp = List(1, 2, 3).map(base+skip*_).filter(isprime).length checkring(r+1, primes+rp, nums+4); } } def answer = checkring(2, 3, 5) } This one is pretty easy after observing that you skip twice the “radius" to get from one corner to the next for a given ring of the spiral.Euler 59
http://samskivert.com/blog/2010/07/euler-59/
Tue, 27 Jul 2010 00:00:00 +0000http://samskivert.com/blog/2010/07/euler-59/Problem 059:
object Euler59 extends EulerApp { val cipher = readline("cipher1.txt") split(',') map(_.toInt) def decode (cipher :Array[Int], key :Array[Char]) = (0 until cipher.length) map(ii => cipher(ii) ^ key(ii%key.length)) def answer = (for { a <- 'a' to 'z'; b <- 'a' to 'z'; c <- 'a' to 'z' val decoded = decode(cipher, Array(a, b, c)) if (decoded.map(_.toChar).mkString.contains(" chapter")) } yield decoded.sum).head } Nothing fancy here. I do a brute force search, trying each key in turn and looking for a particular English word to indicate that the decoding is correct.Euler 60
http://samskivert.com/blog/2010/07/euler-60/
Tue, 27 Jul 2010 00:00:00 +0000http://samskivert.com/blog/2010/07/euler-60/Problem 060:
object Euler60 extends EulerApp { val primes = genprimes(10000) filter(0.!=) val ppairs = Set() ++ (for { ii <- 0 until primes.length-1; jj <- ii until primes.length; val pi = primes(ii); val pj = primes(jj); if (isprime((pi.toString+pj).toInt) && isprime((pj.toString+pi).toInt)) } yield (pi, pj)) def isset (pset :List[Int], prime :Int) = pset.foldLeft(true)((b, a) => b && ppairs((a, prime))) def find (pset :List[Int], plist :List[Int]) :Option[List[Int]] = { if (pset.size == 5) Some(pset) else if (plist.Euler 61
http://samskivert.com/blog/2010/07/euler-61/
Tue, 27 Jul 2010 00:00:00 +0000http://samskivert.com/blog/2010/07/euler-61/Problem 061:
object Euler61 extends EulerApp { case class Pn (card :Int, value :Int) { def valid = (value < 10000) && (value > 999) def ab = value / 100 def cd = value % 100 } def tri (n :Int) = Pn(3, n*(n+1)/2) def square (n :Int) = Pn(4, n*n) def pent (n :Int) = Pn(5, n*(3*n-1)/2) def hex (n :Int) = Pn(6, n*(2*n-1)) def hept (n :Int) = Pn(7, n*(5*n-3)/2) def oct (n :Int) = Pn(8, n*(3*n-2)) def gen (max :Int)(gen :(Int) => Pn) = (1 to max) map(gen) filter(_.Euler 56
http://samskivert.com/blog/2010/07/euler-56/
Mon, 26 Jul 2010 00:00:00 +0000http://samskivert.com/blog/2010/07/euler-56/Problem 056:
object Euler56 extends EulerApp { def answer = (for { a <- 90 to 100; b <- 90 to 100 } yield BigInt(a).pow(b).toString.map(_-'0').sum) max } I'm in Switzerland at the moment, so my mind naturally turns to Project Euler.
I have made some changes to my problem harness. Previously, I relied on Scala's Application class's jiggery pokery to stuff your whole program into a static initializer and execute it.Euler 57
http://samskivert.com/blog/2010/07/euler-57/
Mon, 26 Jul 2010 00:00:00 +0000http://samskivert.com/blog/2010/07/euler-57/Problem 057:
object Euler57 extends EulerApp { case class Frac (numer :BigInt, denom :BigInt) { def add (n :BigInt) = Frac(n * denom + numer, denom) def invert = Frac(denom, numer) def numheavy = numer.toString.length > denom.toString.length } def expand (count :Int) :Frac = if (count == 0) Frac(1, 2) else expand(count-1).add(2).invert def answer = (0 to 1000) filter(i => expand(i).add(1).numheavy) length } I took the opportunity to use a case class to model just enough of a rational to get the job done.Grand Central Corner
http://samskivert.com/blog/2010/07/grand-central-corner/
Sun, 11 Jul 2010 00:00:00 +0000http://samskivert.com/blog/2010/07/grand-central-corner/I have graduated to the ranks of property ownership in sunny Seattle. I present photographic proof for your visual enjoyment.Riddle me this
http://samskivert.com/blog/2010/06/riddle-me-this/
Wed, 09 Jun 2010 00:00:00 +0000http://samskivert.com/blog/2010/06/riddle-me-this/I don’t expect anyone to know the answer to this question, but I’m hoping that bitching about it will improve my mood sufficiently to prepare me for the painful foray into the guts of javac that will be needed to find the answer myself.
There’s a very sophisticated pile of code in com.sun.tools.javac.comp.Infer that infers the type of a universally quantified method application, given its signature and actual parameter types. To clarify what that means, let’s look at some code.Life on the edge (case)
http://samskivert.com/blog/2010/05/life-on-the-edge-case/
Sun, 16 May 2010 00:00:00 +0000http://samskivert.com/blog/2010/05/life-on-the-edge-case/My current research project has given me myriad opportunities to break the Java compiler. Usually, this is because I’m tinkering with its internal data structures in a way that it neither anticipated nor feels especially good about. In such circumstances, I usually apologize profusely and look for a less intrusive way to accomplish my goals. Today however, I managed to cause javac to take umbrage without having first gone rummaging around in its underwear drawer.On space between sentences
http://samskivert.com/blog/2010/02/on-space-between-sentences/
Sat, 06 Feb 2010 00:00:00 +0000http://samskivert.com/blog/2010/02/on-space-between-sentences/In the nineteenth century, which was a dark and inflationary age in typography and type design, many compositors were encouraged to stuff extra spaces between sentences. Generations of twentieth-century typists were taught to do the same, by hitting the spacebar twice after every period. Your typing as well as your typesetting will benefit from unlearning this quaint Victorian habit.
Robert Bringhurst, “The Elements of Typographic Style”
Hear, hear! “Duplicate field expected”
http://samskivert.com/blog/2010/01/duplicate-field-expected/
Sun, 24 Jan 2010 00:00:00 +0000http://samskivert.com/blog/2010/01/duplicate-field-expected/In my recent programming adventures, I separately encountered two perplexing error messages:
RuntimeException: Variable is used without definition! IllegalArgumentException: Duplicate field expected Inspection of the underlying code brought clarity:
throw new RuntimeException("Variable " + m + " used without definition!"); throw new IllegalArgumentException("Duplicate field " + fieldName); The former was reporting a problem with a variable declared as InputStream is, the latter a problem with JUnit’s @Test annotation which defines a parameter java.Euler 52
http://samskivert.com/blog/2010/01/euler-52/
Fri, 01 Jan 2010 00:00:00 +0000http://samskivert.com/blog/2010/01/euler-52/Problem 052:
object Euler52 extends Application { def sort (n :Int) = n.toString.toList.sortWith(_<_).mkString.toInt def g (n :Int, sn :Int) = (2 to 6).forall(m => sort(n*m) == sn) def f (n :Int) = g(n, sort(n)) println(Stream.from(1).find(f).get) } Happy New Year! What better way to ring in the new year than doing math problems while sitting on the lanai under the Hawaiian sun? I'm already up to Euler 90, so I've got some catching up to do with my posts.Euler 53
http://samskivert.com/blog/2010/01/euler-53/
Fri, 01 Jan 2010 00:00:00 +0000http://samskivert.com/blog/2010/01/euler-53/Problem 053:
object Euler53 extends Application { def fact (n :BigInt) :BigInt = if (n < 2) 1 else n * fact(n-1) def choose (n :BigInt, r :BigInt) = fact(n)/(fact(r)*fact(n-r)) println((for (n <- 1 to 100; r <- 1 to n; if (choose(n, r) > 1000000)) yield 1).sum) } Another simple brute force solution. Enumerate and count. BigInt lets us avoid any serious thinking.Euler 54
http://samskivert.com/blog/2010/01/euler-54/
Fri, 01 Jan 2010 00:00:00 +0000http://samskivert.com/blog/2010/01/euler-54/Problem 054:
object Euler54 extends EulerApp { class Card (s :String) { val suit :Char = s.charAt(1) val rank :Int = "23456789TJQKA".indexOf(s.charAt(0)) def > (o :Card) = if (rank == o.rank) suit > o.suit else rank > o.rank } class Hand (c :Seq[Card]) { def groupCards (cards :List[Card]) :List[List[Card]] = if (cards.isEmpty) Nil else { val g = cards.takeWhile(_.rank == cards.head.rank) g :: groupCards(cards.drop(g.length)) } val cards = c.toList.sortWith(_>_) val group = groupCards(cards).Euler 55
http://samskivert.com/blog/2010/01/euler-55/
Fri, 01 Jan 2010 00:00:00 +0000http://samskivert.com/blog/2010/01/euler-55/Problem 055:
object Euler55 extends EulerApp { def ispal (n :String) = n.take(n.length/2) == n.takeRight(n.length/2).reverse def islychrel (n :BigInt, iter :Int = 0) :Int = if (iter > 0 && ispal(n.toString)) 0 else if (iter == 50) 1 else islychrel(n + BigInt(n.toString.reverse), iter+1) println((1 to 9999).map(n => islychrel(n)).sum) } Nothing much to see here, other than that I took advantage of a couple of nice features of Scala 2.8 while cleaning this up for posting.Thank Gosling
http://samskivert.com/blog/2009/11/thank-gosling/
Wed, 04 Nov 2009 00:00:00 +0000http://samskivert.com/blog/2009/11/thank-gosling/The following is not legal Java:
public static void main (String[] args) { int[] foo = new int[1]; int[] bar = new int[1]; ((args.length == 0) ? foo[0] : bar[0]) = 1; } That makes my life easier.Loft Remodel
http://samskivert.com/blog/2009/10/loft-remodel/
Mon, 12 Oct 2009 00:00:00 +0000http://samskivert.com/blog/2009/10/loft-remodel/Shortly before I departed sunny San Francisco, I had my loft remodeled. I finally got some pictures from my contractor as I didn’t have time to take any of my own before I took off. They are here for your viewing pleasure.GWT AsyncGen
http://samskivert.com/blog/2009/10/gwt-asyncgen/
Fri, 09 Oct 2009 00:00:00 +0000http://samskivert.com/blog/2009/10/gwt-asyncgen/The back-breaking straw landed on this camel earlier today when adding some methods to a GWT RemoteService interface and then remembering that, “Oh yeah, I have to go add those manually to the async mirror interface that goes with my service.”
First I poked around on the web. I found some sort of Maven plugin that in theory automatically generates these extra services, but I don’t use Maven and I’m not about to start now.Pike Place
http://samskivert.com/blog/2009/09/pike-place/
Tue, 22 Sep 2009 00:00:00 +0000http://samskivert.com/blog/2009/09/pike-place/I moved to Seattle and have a new place to live. Check out the pictures.Why am I surprised?
http://samskivert.com/blog/2009/09/why-am-i-surprised/
Sun, 20 Sep 2009 00:00:00 +0000http://samskivert.com/blog/2009/09/why-am-i-surprised/I go to set up my My Qwest account page for my glorious new phone service and when I click “Create account” after typing in a bunch of annoying crap, it gives me a page that says “Oh, sorry, our shit is down right now. Try again later.” (I’m paraphrasing.) I try again a few minutes later and it claims that my username already exits. Awesome.
My account must already be created, so I try logging in and get:A technique for type-safe, concise actors in Java
http://samskivert.com/blog/2009/06/a-technique-for-type-safe-concise-actors-in-java/
Wed, 17 Jun 2009 00:00:00 +0000http://samskivert.com/blog/2009/06/a-technique-for-type-safe-concise-actors-in-java/Actors are great. They provide a concurrency model that is not too taxing to reason about and an organizing principle that tends to jive with how you would naturally structure your code. I recently put actors to use in a real project (implemented in Java), and in the process had to overcome some aesthetic difficulties with a technique that seemed worth sharing.
The Itch
The requirements I was trying to satisfy are as follows (note: I realize that most people use the term messages to describe what actors process but I prefer to say that actors process actions, so hopefully you can bear with my rogue nomenclature):iPeggle
http://samskivert.com/blog/2009/06/ipeggle/
Sun, 14 Jun 2009 00:00:00 +0000http://samskivert.com/blog/2009/06/ipeggle/I discovered recently that Peggle is available on the iPhone for $1 and I am simply appalled. I don’t know what to think about a universe where one can obtain, for a single US dollar, a quantity of awesome in proportions so epic as to tax the imagination. It spits in the face of the very notion of value. Next they’ll be selling Ferraris for $7.50 and caviar for $.25 a pound.A Whirled Tour
http://samskivert.com/blog/2009/03/a-whirled-tour/
Thu, 26 Mar 2009 00:00:00 +0000http://samskivert.com/blog/2009/03/a-whirled-tour/I gave a talk at the GDC this year, this time with a more technical bent than the usual business + metrics talks that Daniel and I have established an annual tradition of delivering.
The slides are available here for the curious and indulgent:
http://samskivert.com/work/2009/gdc/WhirledTour.pdf
I dare say it seemed to go over well. At least that was my impression and I have no intention of disabusing myself of it.Brazil + Argentina
http://samskivert.com/blog/2009/03/brazil-argentina/
Sun, 01 Mar 2009 00:00:00 +0000http://samskivert.com/blog/2009/03/brazil-argentina/Lo, it is photodocumentary of my recent trip to South America.Git out of my head
http://samskivert.com/blog/2008/12/git-out-of-my-head/
Mon, 01 Dec 2008 00:00:00 +0000http://samskivert.com/blog/2008/12/git-out-of-my-head/Last night I dreamt about GIT and implementing complex revision control policies atop its basic tools. In my dream I danced around the room as changes were fetched and pushed.OMG Best Cookies Ever
http://samskivert.com/blog/2008/09/omg-best-cookies-ever/
Wed, 03 Sep 2008 00:00:00 +0000http://samskivert.com/blog/2008/09/omg-best-cookies-ever/My friend Jes, who has on multiple occasions humbled me in head to head games of Dictionary Attack (beaten at my own game, oh the humanity), has now thrown down the gauntlet. Behold:
I hope I can eventually come to terms with the fact that her pixel art skills exceed my own in even the squishiest of media.Burning Man 2008
http://samskivert.com/blog/2008/08/burning-man-2008/
Sun, 31 Aug 2008 00:00:00 +0000http://samskivert.com/blog/2008/08/burning-man-2008/Through some combination of subconscious neglect and happy coincidence, I discovered that my camera battery was just about dead when I arrived at Burning Man. Thus I made a quick photo tour shortly after arrival and spent the rest of the event blissfully free of any feeling of responsibility to document my adventures.
The small selection of photos I took before the juice ran out can be seen on Flickr.Euler 050
http://samskivert.com/blog/2008/08/euler-050/
Mon, 18 Aug 2008 00:00:00 +0000http://samskivert.com/blog/2008/08/euler-050/Problem 050:
object Euler50 extends EulerApp { val pvec = genprimes(1000000) val primes = pvec.filter(0.!=) case class PSum (sum :Int, length :Int) { def add (prime :Int) = PSum(sum+prime, length+1) } def fsum (idx :Int, csum :PSum, lsum :PSum) :PSum = { if (idx >= primes.length || csum.sum >= pvec.length) lsum else fsum(idx+1, csum.add(primes(idx)), if (pvec(csum.sum) != 0) csum else lsum) } def longer (one :PSum, two :PSum) = if (one.Euler 051
http://samskivert.com/blog/2008/08/euler-051/
Mon, 18 Aug 2008 00:00:00 +0000http://samskivert.com/blog/2008/08/euler-051/Problem 051:
object Euler51 extends EulerApp { def cprimes (n :String)(d :Char) = { val variants = “0123456789″.toList.map(nd => n.replace(d, nd)) variants.filter(!_.startsWith("0″)).map(Integer.parseInt).filter(isprime).length } def count (prime :String) = { prime.toList.removeDuplicates.map(cprimes(prime)).reduceRight(Math.max) } println(genprimes(150000).filter(0.!=).find(p => count(p.toString) > 7).get) } A robust set of functional libraries really makes our lives easier here. Our function for obtaining the count of primes that can be generated by substituting all digits for one particular digit in the original prime takes our number as a string, turns that into a list of digits, removes duplicates, maps a (curried) function onto each of those individual digits and then folds the resulting list with max to find the largest value.Euler 048
http://samskivert.com/blog/2008/08/euler-048/
Mon, 11 Aug 2008 00:00:00 +0000http://samskivert.com/blog/2008/08/euler-048/Problem 048:
object Euler48 extends Application { println(1.to(1000).map(a => BigInt(a).pow(a)).reduceRight(_+_) % BigInt(10).pow(10)) } The Right Thing ™ here was to not rely on the magic of BigInt, but to do the addition modulo 10^10 as well as to compute the powers modulo 10^10, but laziness and the allure of a one line solution won out in the end.Euler 049
http://samskivert.com/blog/2008/08/euler-049/
Mon, 11 Aug 2008 00:00:00 +0000http://samskivert.com/blog/2008/08/euler-049/Problem 049:
object Euler49 extends EulerApp { def sort (n :Int) = n.toString.toList.sort(_<_).mkString.toInt def isterm (n :Int, nn :Int) = isprime(nn) && sort(nn) == sort(n) def isseq (n :Int) = isterm(n, n+3330) && isterm(n, n+6660) def mkseq (n :Int) = List(n, n+3330, n+6660).mkString println(mkseq(1488.to(10000-6660).filter(isprime).filter(isseq).first)) } This one's been somewhat deconstructed. I originally just wrote a for loop, but then I wanted to make it a bit more functional. Then I wanted to make it a bit shorter.Euler 046
http://samskivert.com/blog/2008/08/euler-046/
Sun, 10 Aug 2008 00:00:00 +0000http://samskivert.com/blog/2008/08/euler-046/Problem 046:
object Euler46 extends EulerApp { def isgold (n :Int) = 1.to(Math.sqrt(n/2)).exists(s => isprime(n-2*s*s)) def check (n :Int) :Int = if (isprime(n) || isgold(n)) check(n+2) else n println(check(3)) } Fortunately this one is easier to disprove than Goldbach's other conjecture. If n = p + 2*s*s, we can simply try all values of s from 1 to the square root of n/2 and check whether n - 2*s*s is prime.Euler 047
http://samskivert.com/blog/2008/08/euler-047/
Sun, 10 Aug 2008 00:00:00 +0000http://samskivert.com/blog/2008/08/euler-047/Problem 047:
object Euler47 extends Application { val factors = Array.make(150000, 0) var idx = 2 while (idx < factors.length) { for (midx <- List.range(idx+idx, factors.length, idx)) factors(midx) += 1 do idx = idx+1 while (idx < factors.length && factors(idx) != 0) } println(1.to(factors.length-3).find(n => factors.slice(n, n+4).mkString == "4444")) } Here we do two things: first, use a modified Sieve of Eratosthenes to count up the unique factors of all numbers up to some maximum value (which cheat and choose to be “large enough").The Trans-Siberian Express
http://samskivert.com/blog/2008/08/the-transsiberian-express/
Thu, 07 Aug 2008 00:00:00 +0000http://samskivert.com/blog/2008/08/the-transsiberian-express/Erin and I traveled across Russia on the Golden Eagle Trans-Siberian Express this June and we have the pictures to prove it. At the time of this posting, they’re not fully annotated, but I can’t imagine anyone will want to reexperience all 360 hours of travel across Russia in picto-narrative form anyway, so just look at the thumbnails and see if anything jumps out at you.
Vladivostok Khabarovsk Ulan Bataar Along the Way Ulan Ude Lake Baikal Port Baikal + Listvyanka Irkutsk Krasnoyarsk Novosibirsk Yekaterinburg Kazan’ Steam Engine Moscow Russia is a big country.Euler 044
http://samskivert.com/blog/2008/07/euler-044/
Sun, 20 Jul 2008 00:00:00 +0000http://samskivert.com/blog/2008/07/euler-044/Problem 044:
object Euler44 extends Application { def pent (n :Int) = n*(3*n-1)/2 val pents = Set() ++ List.range(1, 3000).map(pent) def find (a :Int, b :Int) :Int = { val pa = pent(a) val pb = pent(b) val d = pb-pa val s = pa+pb if (pents.contains(d) && pents.contains(s)) d else if (a >= b) find(1, b+1) else find(a+1, b) } println(find(1, 2)) } This one's not especially elegant or clever (but it is fast).Euler 045
http://samskivert.com/blog/2008/07/euler-045/
Sun, 20 Jul 2008 00:00:00 +0000http://samskivert.com/blog/2008/07/euler-045/Problem 045:
object Euler45 extends Application { def findh (pent :Long, h :Long) :Long = { val hex = h*(2*h-1) if (hex > pent) findh(pent, h-1) else if (hex < pent) 0 else hex } def findp (tri :Long, p :Long) :Long = { val pent = p*(3*p-1)/2 if (pent > tri) findp(tri, p-1) else if (pent < tri) 0 else findh(pent, p-1) } def find (t :Long) :Long = { val n = findp(t*(t+1)/2, t-1) if (n !Hail Caesar
http://samskivert.com/blog/2008/07/hail-caesar/
Sun, 20 Jul 2008 00:00:00 +0000http://samskivert.com/blog/2008/07/hail-caesar/Went to see a performance of Verdi’s Requiem last night at the Roman Theater in Orange. We arrived just as the show was starting and had to do battle at the ticket office and again at the gate to actually get in, but the trouble was worth it as the (unfortunately blurry) picture shows:Euler 043
http://samskivert.com/blog/2008/07/euler-043/
Sat, 19 Jul 2008 00:00:00 +0000http://samskivert.com/blog/2008/07/euler-043/Problem 043:
object Euler43 extends Application { def compsum (n :Long, digits :List[Int], divs :List[Int], sum :Long) :Long = { if (digits.isEmpty) n + sum else (for { d <- digits; val nn = n*10 + d; if ((nn%1000) % divs.head == 0) } yield compsum(nn, digits-d, divs.tail, sum)).foldLeft(0L)(_+_) } def digits (n :Int) = n.toString.toList.map(_-'0') def norepeats (n :Int) = digits(n).removeDuplicates == digits(n) def compute (s :Int) = compsum(s, 0.Le Tour
http://samskivert.com/blog/2008/07/le-tour/
Sat, 19 Jul 2008 00:00:00 +0000http://samskivert.com/blog/2008/07/le-tour/The Tour de France happened to be passing about 5km from where I’m staying (near Les Baux des Provence), so naturally a viewing was in order. The first group came and went in the span of about two seconds:
Then maybe half a minute later the second, much larger, group whizzed by. They were a bit more spread out, turning to single file after this short red clump at the head:Euler 039
http://samskivert.com/blog/2008/06/euler-039/
Sun, 01 Jun 2008 00:00:00 +0000http://samskivert.com/blog/2008/06/euler-039/Problem 039:
object Euler39 extends Application { def sols (perim :Int) = perim + 1000 * (for { a <- List.range(1, perim/2); b <- List.range(1, (perim-a)/2+1); c <- List(perim-a-b); if (a*a + b*b == c*c) } yield 1).length; println(List.range(3, 1000).map(sols).foldLeft(0)(Math.max) % 1000); } Nothing fancy here, just a moderately brute force search.Euler 040
http://samskivert.com/blog/2008/06/euler-040/
Sun, 01 Jun 2008 00:00:00 +0000http://samskivert.com/blog/2008/06/euler-040/Problem 040:
object Euler40 extends Application { val digits = List.range(1, 200000).flatMap(n => n.toString.toList).map(_-'0'); println(List(0, 9, 99, 999, 9999, 99999, 999999).foldRight(1)((idx, b) => b * digits(idx))); } Another straightforward solution that's nicely accommodated by our basic tools. Generate a list of the first 200,000 integers, split those into lists of each individual integer's digits and flatmap them into one contiguous list. Then extract the digits at our desired indices and multiply them.Euler 041
http://samskivert.com/blog/2008/06/euler-041/
Sun, 01 Jun 2008 00:00:00 +0000http://samskivert.com/blog/2008/06/euler-041/Problem 041:
object Euler41 extends EulerApp { def perms (d :List[Char], n :List[Char]) :List[Int] = d match { case Nil => n.mkString.toInt :: Nil; case _ => d.flatMap(digit => perms(d.filter(digit.!=), digit :: n)) } println(perms("1234567″.toList, Nil).filter(isprime).foldLeft(0)(Math.max)); } We save ourselves many CPU cycles by noticing that a pandigital number with 1 through 9 will always have digits that sum to 45, and similarly one with 1 through 8 will always have digits that sum to 36.Euler 042
http://samskivert.com/blog/2008/06/euler-042/
Sun, 01 Jun 2008 00:00:00 +0000http://samskivert.com/blog/2008/06/euler-042/Problem 042:
object Euler42 extends EulerApp { def wvalue (word :Seq[Char]) = word.foldLeft(0)((s, l) => (s + (l - 'A' + 1))) def tri (n :Int) = (n*(n+1))/2 println(readwords("words.txt").map(wvalue).filter(v => (v == tri(Math.sqrt(2*v)))).length); } This one is kind of cheating. I discovered (using the terminology tri = (n * (n+1))/2) that floor(sqrt(2*tri)) == n for at least the first 10,000 values of n. This isn't hugely surprising because 2*tri = (n*n + n), so the square root of that is always going to be a bit bigger than n, and floor of that could well take us right to the integer we need.What in the Whirled?
http://samskivert.com/blog/2008/03/what-in-the-whirled/
Tue, 25 Mar 2008 00:00:00 +0000http://samskivert.com/blog/2008/03/what-in-the-whirled/Hey, here’s the crazy project that’s been consuming the last year and a half of my life:
How handy that it can be embedded right into my blog. At some point we’ll fix the URL clicking, but for now you can check it out for reals at www.whirled.com.Euler 033
http://samskivert.com/blog/2008/02/euler-033/
Mon, 25 Feb 2008 00:00:00 +0000http://samskivert.com/blog/2008/02/euler-033/Problem 033:
object Euler33 extends Application { def equal (ratio :Double, rnum :Int, rdenom :Int) :Boolean = { (rdenom > 0) && (ratio == rnum/rdenom.doubleValue()); } val fracs = for { denom <- List.range(10,100) num <- List.range(10,denom) if ((num%10 == denom/10 && equal(num/denom.doubleValue(), num/10, denom%10)) || (num/10 == denom%10 && equal(num/denom.doubleValue(), num%10, denom/10))) } yield Pair(num, denom); val prod = fracs.foldRight(Pair(1,1))((b, a) => (Pair(b._1 * a._1, b._2 * a._2))); println(prod._2 / prod.Euler 034
http://samskivert.com/blog/2008/02/euler-034/
Mon, 25 Feb 2008 00:00:00 +0000http://samskivert.com/blog/2008/02/euler-034/Problem 034:
object Euler34 extends Application { val facts = Array(1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880); def digfact (sum :Int, n :Int) :Int = if (n == 0) sum else digfact(facts(n % 10) + sum, n/10); def check (sum :Int, n :Int) :Int = if (n == 2000000) sum; else if (digfact(0, n) == n) check(sum+n, n+1); else check(sum, n+1); println(check(0, 10)); } Since we're only computing factorial for single digit numbers, we pre-compute the values of 0 through 9 factorial and then breeze up through the positive integers accumulating all numbers that meet our criterion.Euler 035
http://samskivert.com/blog/2008/02/euler-035/
Mon, 25 Feb 2008 00:00:00 +0000http://samskivert.com/blog/2008/02/euler-035/Problem 035:
object Euler35 extends EulerApp { val primes = genprimes(1000000); def digits (value :Int) :Int = if (value == 0) 0 else 1 + digits(value/10); def rotate (value :Int, turns :Int) :Int = { val mod = Math.pow(10, digits(value)-turns).intValue() (value % mod) * Math.pow(10, turns).intValue() + (value / mod) } def circprime (n :Int) :Boolean = { List.range(0, digits(n)).foldRight(true)((t, b) => (b && (primes(rotate(n, t)) != 0))) } println(primes.filter(0.!=).filter(circprime).length); } Coming up with rotate() was fun and the rest was pretty straightforward.Euler 036
http://samskivert.com/blog/2008/02/euler-036/
Mon, 25 Feb 2008 00:00:00 +0000http://samskivert.com/blog/2008/02/euler-036/Problem 036:
object Euler36 extends Application { def ispal (n :String) = n.reverse.sameElements(n) def bothpal (n :Int) = ispal(n.toString) && ispal(n.toBinaryString) println(List.range(1, 1000000, 2).filter(bothpal).foldRight(0)(_+_)); } Brief, readable and reasonably efficient, yay for Scala. The only cleverness here is to realize that binary palindromes must be odd.Euler 037
http://samskivert.com/blog/2008/02/euler-037/
Mon, 25 Feb 2008 00:00:00 +0000http://samskivert.com/blog/2008/02/euler-037/Problem 037:
object Euler37 extends EulerApp { val primes = genprimes(1000000); def isrtrunc (prime :Int) :Boolean = (prime == 0) || ((primes(prime) != 0) && isrtrunc(prime/10)); def isltrunc (prime :String) :Boolean = prime.isEmpty || ((primes(prime.toInt) != 0) && isltrunc(prime.substring(1))); def istrunc (prime :Int) = isrtrunc(prime) && isltrunc(prime.toString) println(primes.drop(10).filter(0.!=).filter(istrunc).foldRight(0)(_+_)); } I cheated a little and turned the integer into a string in order to easily truncate it from the left, it would perhaps have been more elegant to take the value modulo 10digits-1 but the code would have been longer and I feel an irrational desire for brevity in these solutions.Euler 038
http://samskivert.com/blog/2008/02/euler-038/
Mon, 25 Feb 2008 00:00:00 +0000http://samskivert.com/blog/2008/02/euler-038/Problem 038:
object Euler38 extends Application { def ispan (n :String) = n.toList.sort(_<_).mkString == "123456789"; def catprod (n :Int, r :Int) = List.range(1, r+1).flatMap(p => (n*p).toString.toList) def find (n :Int, r :Int, max :Int) :Int = { val cp = catprod(n, r); if (cp.length > 9) if (r == 2) max else find(n, r-1, max); else if (ispan(cp)) find(n+1, r, Math.max(cp.mkString.toInt, max)) else find(n+1, r, max); } println(find(1, 5, 0)); } I wrote the above general solution which computes the concatenated product with (1, 2, 3, 4, 5) for increasing values of n until the product exceeds 9 digits, then moves down to (1, 2, 3, 4) and so on.Euler 028
http://samskivert.com/blog/2008/02/euler-028/
Sat, 23 Feb 2008 00:00:00 +0000http://samskivert.com/blog/2008/02/euler-028/Problem 028:
object Euler28 extends Application { def spiral (size :Int) :Int = { if (size == 1) return 1; val smaller = size-2; spiral(smaller) + 4*(smaller*smaller) + (1+2+3+4)*(smaller+1); } println(spiral(1001)); } This is a slightly brevified version of my original solution which is a bit clearer:
val smaller = size-2; val start = smaller*smaller; val step = smaller+1; return spiral(smaller) + ((start + 1*step) + (start + 2*step) + (start + 3*step) + (start + 4*step)); Looking at the grid:Euler 029
http://samskivert.com/blog/2008/02/euler-029/
Sat, 23 Feb 2008 00:00:00 +0000http://samskivert.com/blog/2008/02/euler-029/Problem 029:
object Euler29 extends Application { println((for { a <- List.range(2, 101) b <- List.range(2, 101) } yield BigInt(a).pow(b)).removeDuplicates.length); } This one's pretty easy thanks to BigInt.Euler 030
http://samskivert.com/blog/2008/02/euler-030/
Sat, 23 Feb 2008 00:00:00 +0000http://samskivert.com/blog/2008/02/euler-030/Problem 030:
object Euler30 extends Application { def digits (n :Int) = n.toString.toList.map(c => c - '0'); def issum5 (n :Int) = digits(n).map(a => Math.pow(a, 5).intValue()).foldRight(0)(_+_) == n; println(List.range(2, 200000).filter(issum5).foldRight(0)(_+_)); } A decent balance of compactness and readability, IMHO. I would like to do away with the 200,000 upper limit which I came to via some preparatory noodling.Euler 031
http://samskivert.com/blog/2008/02/euler-031/
Sat, 23 Feb 2008 00:00:00 +0000http://samskivert.com/blog/2008/02/euler-031/Problem 031:
object Euler31 extends Application { def perms (remain :Int, coins :List[Int]) :Int = { if (remain == 0) return 1; else if (coins == Nil) return 0; else List.range(0, remain/coins.head+1).map( q => perms(remain - q*coins.head, coins.tail)).foldRight(0)(_+_); } println(perms(200, List(200, 100, 50, 20, 10, 5, 2, 1))); } Nothing too fancy here, just enumerate all legal quantities of the first coin in the list (including zero), then recurse with that coin removed from the list and its value times the number chosen removed from the sum.Euler 032
http://samskivert.com/blog/2008/02/euler-032/
Sat, 23 Feb 2008 00:00:00 +0000http://samskivert.com/blog/2008/02/euler-032/Problem 032:
object Euler32 extends Application { def digits (n :Int) = n.toString.toList.map(c => c - '0'); def ispan (a :Int, b :Int, n :Int) :Boolean = (digits(a) ::: digits(n) ::: digits(b)).sort(_<_).equals(List.range(1,10)); def haspanfact (n :Int) :Boolean = List.range(2, 100).find((a) => (n % a == 0 && ispan(a, n/a, n))) != None; println(List.range(1000, 10000).filter(haspanfact).foldRight(0)(_+_)); } We want a factorization of a four digit number (which will be either two digits times three or one digit times four), so we enumerate all 4 digit numbers from 1000 to 9999, filter them by checking all possible one and two digit divisors first for divisibility and second for pandigitality, then sum the matches.Euler 024
http://samskivert.com/blog/2008/02/euler-024/
Sun, 03 Feb 2008 00:00:00 +0000http://samskivert.com/blog/2008/02/euler-024/Problem 024:
object Euler24 extends Application { def fact (n: Int): Int = if (n == 0) 1 else n * fact(n - 1) def nthperm (target :Int, nums :List[Int]) :String = { if (nums.length == 1) return nums(0).toString; val nfact = fact(nums.length-1) val idx = (target / nfact).intValue; val digit = nums(idx); return digit + nthperm(target - nfact*idx, nums.filter(digit.!=)); } println(nthperm(1000000, List.range(0, 10))); } We know there are 362880 (9!Euler 025
http://samskivert.com/blog/2008/02/euler-025/
Sun, 03 Feb 2008 00:00:00 +0000http://samskivert.com/blog/2008/02/euler-025/Problem 025:
object Euler25 extends Application { var prev2 :BigInt = 1; var prev1 :BigInt = 1; var value :BigInt = prev2 + prev1; var term = 3; while (value.toString.length < 1000) { prev2 = prev1; prev1 = value; value = prev1 + prev2; term += 1; } println(term); } Another unglamorous solution wherein all the hard work is done by BigInt.Euler 026
http://samskivert.com/blog/2008/02/euler-026/
Sun, 03 Feb 2008 00:00:00 +0000http://samskivert.com/blog/2008/02/euler-026/Problem 026:
object Euler26 extends Application { def divcycle (numer :Int, denom :Int, rlist :List[Int]) :Int = { val remain = numer % denom; if (remain == 0) return 0; val ridx = rlist.indexOf(remain); if (ridx >= 0) ridx+1 else divcycle(remain * 10, denom, remain :: rlist); } var cycles = List.range(1, 1000).map(v => divcycle(1, v, Nil)); println(cycles.indexOf(cycles.foldRight(0)(Math.max))+1); } This one turned out to be easy once I realized that the key was looking at the remainder after each step in the long division process.Euler 027
http://samskivert.com/blog/2008/02/euler-027/
Sun, 03 Feb 2008 00:00:00 +0000http://samskivert.com/blog/2008/02/euler-027/Problem 027:
object Euler27 extends EulerApp { val MAX_N = 80; val primes = genprimes(MAX_N*MAX_N + MAX_N*1000 + 1000); def polyprimes (primes :Array[Int], a :Int, b :Int, n :Int) :Int = if (primes(Math.abs(n*n + a*n + b)) == 0) 0 else 1 + polyprimes(primes, a, b, n+1); val polys = for { a <- List.range(-1000, 1000) b <- List.range(-1000, 1000) p <- List(polyprimes(primes, a, b, 0)) if (p > 0) } yield Pair(a * b, p); println(polys.Euler 023
http://samskivert.com/blog/2008/01/euler-023/
Sat, 19 Jan 2008 00:00:00 +0000http://samskivert.com/blog/2008/01/euler-023/Problem 023:
import scala.collection.mutable.Set; object Euler23 extends Application { def sumdiv (x :Int) :Int = (1 :: List.flatten(for { divis <- List.range(2, Math.sqrt(x)+1) if x % divis == 0 } yield List(divis, x / divis).removeDuplicates)).foldLeft(0)(_+_); val max = 28123; val abundant = List.range(1, max+1).filter(a => (a < sumdiv(a))).toArray; def filter (abund :Array[Int], ints :Set[Int], a :Int, b :Int) :Set[Int] = { ints -= (abund(a) + abund(b)); if (b == abund.length-1) if (a == abund.Euler 017
http://samskivert.com/blog/2008/01/euler-017/
Fri, 18 Jan 2008 00:00:00 +0000http://samskivert.com/blog/2008/01/euler-017/Problem 017:
object Euler17 extends Application { val ones = Array("", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"); val tens = Array("ten", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"); val teens = Array("ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"); def speak (number :Int) :String = { if (number >= 1000) { return "onethousand"; } else if (number >= 100) { if (number % 100 == 0) { return speak(number/100) + "hundred"; } else { return speak(number/100) + "hundredand" + speak(number%100); } } else if (number >= 20) { if (number % 10 == 0) { return tens(number/10-1); } else { return tens(number/10-1) + speak(number%10); } } else if (number >= 10) { return teens(number-10); } else { return ones(number); } } println(List.Euler 018
http://samskivert.com/blog/2008/01/euler-018/
Fri, 18 Jan 2008 00:00:00 +0000http://samskivert.com/blog/2008/01/euler-018/Problem 018:
object Euler18 extends Application { val triangle = List( 4, 62, 98, 27, 23, 9, 70, 98, 73, 93, 38, 53, 60, 4, 23, 63, 66, 4, 68, 89, 53, 67, 30, 73, 16, 69, 87, 40, 31, 91, 71, 52, 38, 17, 14, 91, 43, 58, 50, 27, 29, 48, 70, 11, 33, 28, 77, 73, 17, 78, 39, 68, 17, 57, 53, 71, 44, 65, 25, 43, 91, 52, 97, 51, 14, 41, 48, 72, 33, 47, 32, 37, 16, 94, 29, 41, 41, 26, 56, 83, 40, 80, 70, 33, 99, 65, 4, 28, 6, 16, 70, 92, 88, 2, 77, 73, 7, 63, 67, 19, 1, 23, 75, 3, 34, 20, 4, 82, 47, 65, 18, 35, 87, 10, 17, 47, 82, 95, 64, 75 ); def fold (triangle :List[Int], max :List[Int]) :Int = { if (max.Euler 019
http://samskivert.com/blog/2008/01/euler-019/
Fri, 18 Jan 2008 00:00:00 +0000http://samskivert.com/blog/2008/01/euler-019/Problem 019:
object Euler19 extends Application { def norm (days :Int) :Function1[Int,Int] = ((year :Int) => (days)); def leap (days :Int) :Function1[Int,Int] = ((year :Int) => { if ((year % 4 == 0) && (year % 100 != 0 || year % 400 == 0)) days+1; else days; }); val length = Array(norm(31), leap(28), norm(31), norm(30), norm(31), norm(30), norm(31), norm(31), norm(30), norm(31), norm(30), norm(31)); println((for (year <- List.range(1900, 2001); month <- List.Euler 020
http://samskivert.com/blog/2008/01/euler-020/
Fri, 18 Jan 2008 00:00:00 +0000http://samskivert.com/blog/2008/01/euler-020/Problem 020:
object Euler20 extends Application { def fact (n: BigInt): BigInt = if (n == 0) 1 else n * fact(n - 1) println(fact(100).toString().foldRight(0)((a, b) => (b + (a - '0')))); } Another one where BigInt does all the heavy lifting.Euler 021
http://samskivert.com/blog/2008/01/euler-021/
Fri, 18 Jan 2008 00:00:00 +0000http://samskivert.com/blog/2008/01/euler-021/Problem 021:
object Euler21 extends Application { def sumdiv (n :Int) = List.range(1, n/2+1).filter(div => n % div == 0).foldLeft(0)(_+_) println(List.range(1, 10000).filter(n => { val sdn = sumdiv(n); (n == sumdiv(sdn) && n != sdn && sdn < 10000) }).foldLeft(0)(_+_)); } This one is almost readable — if you've been staring at a lot of Scala recently. It also uses a less efficient method for computing divisors because it fits on one line.Euler 022
http://samskivert.com/blog/2008/01/euler-022/
Fri, 18 Jan 2008 00:00:00 +0000http://samskivert.com/blog/2008/01/euler-022/Problem 022:
import scala.io.Source; object Euler22 extends Application { def trim (name :String) = name.slice(1, name.length-1); val names = Source.fromFile("names.txt").getLine(0).split(',').map(trim).toList.sort(_<_); def score (name :String) = name.foldLeft(0)((s, l) => (s + (l - 'A' + 1))) println(List.range(0, names.length).map(i => ((i+1) * score(names(i)))).foldLeft(0)(_+_)); } Another reasonably legible solution. I resisted the urge to do it all in a single expression.
I can see how language designers might succumb to the urge to expose a loop counter in their iteration functions because it would be nice to do:Euler 015
http://samskivert.com/blog/2008/01/euler015/
Thu, 17 Jan 2008 00:00:00 +0000http://samskivert.com/blog/2008/01/euler015/Problem 015:
object Euler15 extends Application { val size = 20; def fact (n: BigInt): BigInt = if (n == 0) 1 else n * fact(n - 1) println(fact(size * 2) / (fact(size) * fact(size))) } I first started thinking about this as a caching problem, having just finished problem 14 which was reduced to a reasonable runtime by caching. At any coordinate in the grid, there are some number of unique paths from that position to the destination, so one could start in the bottom right and traverse the graph breadth first from the end to the start, caching the number of paths at each intersection and using that to efficiently compute the number of paths as you made your way to the start.Euler 016
http://samskivert.com/blog/2008/01/euler016/
Thu, 17 Jan 2008 00:00:00 +0000http://samskivert.com/blog/2008/01/euler016/Problem 016:
object Euler16 extends Application { println(BigInt(2).pow(1000).toString().foldRight(0) {(a, b) => (b + (a - '0'))}); } This one almost seemed like cheating, since BigInt takes care of all the hard work for me.Euler 013
http://samskivert.com/blog/2008/01/euler-013/
Wed, 16 Jan 2008 00:00:00 +0000http://samskivert.com/blog/2008/01/euler-013/Problem 013:
object Euler13 extends Application { val data = List("37107287533902102798797998220837590246510135740250", "46376937677490009712648124896970078050417018260538", "74324986199524741059474233309513058123726617309629", "91942213363574161572522430563301811072406154908250", "23067588207539346171171980310421047513778063246676", "89261670696623633820136378418383684178734361726757", "28112879812849979408065481931592621691275889832738", "44274228917432520321923589422876796487670272189318", "47451445736001306439091167216856844588711603153276", "70386486105843025439939619828917593665686757934951", "62176457141856560629502157223196586755079324193331", "64906352462741904929101432445813822663347944758178", "92575867718337217661963751590579239728245598838407", "58203565325359399008402633568948830189458628227828", "80181199384826282014278194139940567587151170094390", "35398664372827112653829987240784473053190104293586", "86515506006295864861532075273371959191420517255829", "71693888707715466499115593487603532921714970056938", "54370070576826684624621495650076471787294438377604", "53282654108756828443191190634694037855217779295145", "36123272525000296071075082563815656710885258350721", "45876576172410976447339110607218265236877223636045", "17423706905851860660448207621209813287860733969412", "81142660418086830619328460811191061556940512689692", "51934325451728388641918047049293215058642563049483", "62467221648435076201727918039944693004732956340691", "15732444386908125794514089057706229429197107928209", "55037687525678773091862540744969844508330393682126", "18336384825330154686196124348767681297534375946515", "80386287592878490201521685554828717201219257766954", "78182833757993103614740356856449095527097864797581", "16726320100436897842553539920931837441497806860984", "48403098129077791799088218795327364475675590848030", "87086987551392711854517078544161852424320693150332", "59959406895756536782107074926966537676326235447210", "69793950679652694742597709739166693763042633987085", "41052684708299085211399427365734116182760315001271", "65378607361501080857009149939512557028198746004375", "35829035317434717326932123578154982629742552737307", "94953759765105305946966067683156574377167401875275", "88902802571733229619176668713819931811048770190271", "25267680276078003013678680992525463401061632866526", "36270218540497705585629946580636237993140746255962", "24074486908231174977792365466257246923322810917141", "91430288197103288597806669760892938638285025333403", "34413065578016127815921815005561868836468420090470", "23053081172816430487623791969842487255036638784583", "11487696932154902810424020138335124462181441773470", "63783299490636259666498587618221225225512486764533", "67720186971698544312419572409913959008952310058822", "95548255300263520781532296796249481641953868218774", "76085327132285723110424803456124867697064507995236", "37774242535411291684276865538926205024910326572967", "23701913275725675285653248258265463092207058596522", "29798860272258331913126375147341994889534765745501", "18495701454879288984856827726077713721403798879715", "38298203783031473527721580348144513491373226651381", "34829543829199918180278916522431027392251122869539", "40957953066405232632538044100059654939159879593635", "29746152185502371307642255121183693803580388584903", "41698116222072977186158236678424689157993532961922", "62467957194401269043877107275048102390895523597457", "23189706772547915061505504953922979530901129967519", "86188088225875314529584099251203829009407770775672", "11306739708304724483816533873502340845647058077308", "82959174767140363198008187129011875491310547126581", "97623331044818386269515456334926366572897563400500", "42846280183517070527831839425882145521227251250327", "55121603546981200581762165212827652751691296897789", "32238195734329339946437501907836945765883352399886", "75506164965184775180738168837861091527357929701337", "62177842752192623401942399639168044983993173312731", "32924185707147349566916674687634660915035914677504", "99518671430235219628894890102423325116913619626622", "73267460800591547471830798392868535206946944540724", "76841822524674417161514036427982273348055556214818", "97142617910342598647204516893989422179826088076852", "87783646182799346313767754307809363333018982642090", "10848802521674670883215120185883543223812876952786", "71329612474782464538636993009049310363619763878039", "62184073572399794223406235393808339651327408011116", "66627891981488087797941876876144230030984490851411", "60661826293682836764744779239180335110989069790714", "85786944089552990653640447425576083659976645795096", "66024396409905389607120198219976047599490197230297", "64913982680032973156037120041377903785566085089252", "16730939319872750275468906903707539413042652315011", "94809377245048795150954100921645863754710598436791", "78639167021187492431995700641917969777599028300699", "15368713711936614952811305876380278410754449733078", "40789923115535562561142322423255033685442488917353", "44889911501440648020369068063960672322193204149535", "41503128880339536053299340368006977710650566631954", "81234880673210146739058568557934581403627822703280", "82616570773948327592232845941706525094512325230608", "22918802058777319719839450180888072429661980811197", "77158542502016545090413245809786882778948721859617", "72107838435069186155435662884062257473692284509516", "20849603980134001723930671666823555245252804609722", "53503534226472524250874054075591789781264330331690"); def toList (number :String) :List[Int] = { number.Euler 014
http://samskivert.com/blog/2008/01/euler-014/
Wed, 16 Jan 2008 00:00:00 +0000http://samskivert.com/blog/2008/01/euler-014/Problem 014:
import scala.collection.mutable.Map; object Euler14 extends Application { var seen :Map[Long,Int] = Map(); def iterate (value :Long) :Int = { val seenlen :Option[Int] = seen.get(value); if (seenlen != None) { return seenlen.get; } else if (value == 1) { return 1; } else if (value % 2 == 0) { val newlen = iterate(value/2)+1; seen.put(value, newlen); return newlen; } else { val newlen = iterate(3*value+1)+1; seen.put(value, newlen); return newlen; } } var longest = List.Euler 009
http://samskivert.com/blog/2008/01/euler-009/
Sat, 12 Jan 2008 00:00:00 +0000http://samskivert.com/blog/2008/01/euler-009/Problem 009:
object Euler9 extends Application { for (a <- List.range(1, 1000); b <- List.range(a, 1000); c <- List.range(b, 1000); if (a*a + b*b == c*c && a+b+c == 1000)) println(a*b*c); } Sequence comprehensions coming in handy here.Euler 010
http://samskivert.com/blog/2008/01/euler-010/
Sat, 12 Jan 2008 00:00:00 +0000http://samskivert.com/blog/2008/01/euler-010/Problem 010:
object Euler10 extends Application { var numbers = List.range(2,1000000).toArray; def sumprimes (idx :Int, sum :Long) :Long = { var prime = numbers(idx); for (midx <- List.range(idx, numbers.length, prime)) { numbers(midx) = 0; } val nidx = numbers.slice(idx, numbers.length).findIndexOf((a) => (a != 0)); if (nidx == -1) return sum + prime; else return sumprimes(idx + nidx, sum + prime); } println(sumprimes(0, 0)); } This one felt like it could have been solved more concisely given more thought.Euler 011
http://samskivert.com/blog/2008/01/euler-011/
Sat, 12 Jan 2008 00:00:00 +0000http://samskivert.com/blog/2008/01/euler-011/Problem 011:
object Euler11 extends Application { val data = Array( 8, 2, 22, 97, 38, 15, 0, 40, 0, 75, 4, 5, 7, 78, 52, 12, 50, 77, 91, 8, 49, 49, 99, 40, 17, 81, 18, 57, 60, 87, 17, 40, 98, 43, 69, 48, 4, 56, 62, 0, 81, 49, 31, 73, 55, 79, 14, 29, 93, 71, 40, 67, 53, 88, 30, 3, 49, 13, 36, 65, 52, 70, 95, 23, 4, 60, 11, 42, 69, 24, 68, 56, 1, 32, 56, 71, 37, 2, 36, 91, 22, 31, 16, 71, 51, 67, 63, 89, 41, 92, 36, 54, 22, 40, 40, 28, 66, 33, 13, 80, 24, 47, 32, 60, 99, 3, 45, 2, 44, 75, 33, 53, 78, 36, 84, 20, 35, 17, 12, 50, 32, 98, 81, 28, 64, 23, 67, 10, 26, 38, 40, 67, 59, 54, 70, 66, 18, 38, 64, 70, 67, 26, 20, 68, 2, 62, 12, 20, 95, 63, 94, 39, 63, 8, 40, 91, 66, 49, 94, 21, 24, 55, 58, 5, 66, 73, 99, 26, 97, 17, 78, 78, 96, 83, 14, 88, 34, 89, 63, 72, 21, 36, 23, 9, 75, 0, 76, 44, 20, 45, 35, 14, 0, 61, 33, 97, 34, 31, 33, 95, 78, 17, 53, 28, 22, 75, 31, 67, 15, 94, 3, 80, 4, 62, 16, 14, 9, 53, 56, 92, 16, 39, 5, 42, 96, 35, 31, 47, 55, 58, 88, 24, 0, 17, 54, 24, 36, 29, 85, 57, 86, 56, 0, 48, 35, 71, 89, 7, 5, 44, 44, 37, 44, 60, 21, 58, 51, 54, 17, 58, 19, 80, 81, 68, 5, 94, 47, 69, 28, 73, 92, 13, 86, 52, 17, 77, 4, 89, 55, 40, 4, 52, 8, 83, 97, 35, 99, 16, 7, 97, 57, 32, 16, 26, 26, 79, 33, 27, 98, 66, 88, 36, 68, 87, 57, 62, 20, 72, 3, 46, 33, 67, 46, 55, 12, 32, 63, 93, 53, 69, 4, 42, 16, 73, 38, 25, 39, 11, 24, 94, 72, 18, 8, 46, 29, 32, 40, 62, 76, 36, 20, 69, 36, 41, 72, 30, 23, 88, 34, 62, 99, 69, 82, 67, 59, 85, 74, 4, 36, 16, 20, 73, 35, 29, 78, 31, 90, 1, 74, 31, 49, 71, 48, 86, 81, 16, 23, 57, 5, 54, 1, 70, 54, 71, 83, 51, 54, 69, 16, 92, 33, 48, 61, 43, 52, 1, 89, 19, 67, 48); val side = Math.Euler 012
http://samskivert.com/blog/2008/01/euler-012/
Sat, 12 Jan 2008 00:00:00 +0000http://samskivert.com/blog/2008/01/euler-012/Problem 012:
object Euler12 extends Application { def findnum (i :Int, x :Int) :Int = { var divs = List.flatten(for { div <- List.range(1, Math.sqrt(x)+1) if x % div == 0 } yield List(div, x / div).removeDuplicates); if (divs.length > 500) return x; else return findnum(i+1, x+i); } println(findnum(1, 0)); } Pretty straightforward, just compute the triangle numbers incrementally and stop when we find one with over 500 divisors.Euler 001
http://samskivert.com/blog/2008/01/euler-001/
Wed, 09 Jan 2008 00:00:00 +0000http://samskivert.com/blog/2008/01/euler-001/I've been doing the Project Euler problems in Scala both because they're fun and as an excuse to play more with Scala and to remind myself of how much fun it is to write functional programs.
I figured it would be fun to post my solutions, inelegant as they may be. Anyone also doing the problems will have to avert their eyes if they see a solution to a problem they've not yet solved.Euler 002
http://samskivert.com/blog/2008/01/euler-002/
Wed, 09 Jan 2008 00:00:00 +0000http://samskivert.com/blog/2008/01/euler-002/Problem 002:
object Euler2 extends Application { def fibby (a :Int, b :Int) :Int = { val next = a + b; return (if (b % 2 == 0) b else 0) + (if (next > 1000000) 0 else fibby(b, next)); } println(fibby(1, 2)); }Euler 003
http://samskivert.com/blog/2008/01/euler-003/
Wed, 09 Jan 2008 00:00:00 +0000http://samskivert.com/blog/2008/01/euler-003/Problem 003:
object Euler3 extends Application { def lpf (divis :Long, divid :Long) :Long = { if (divid % divis == 0) lpf(2, divid/divis) else if (divis > Math.sqrt(divid)) divid else lpf(divis+1, divid) } println(lpf(2l, 317584931803l)); }Euler 004
http://samskivert.com/blog/2008/01/euler-004/
Wed, 09 Jan 2008 00:00:00 +0000http://samskivert.com/blog/2008/01/euler-004/Problem 004:
object Euler4 extends Application { def palindrome (value :String) :Boolean = { val half :Int = value.length()/2; return value.substring(0, half) == value.substring(half).reverse.mkString("","",""); } var palindromes :List[Int] = for { a <- List.range(100, 999) b <- List.range(100, 999) if palindrome(String.valueOf(a * b)) } yield a*b; println(palindromes.sort((a, b) => a<b )); }Euler 005
http://samskivert.com/blog/2008/01/euler-005/
Wed, 09 Jan 2008 00:00:00 +0000http://samskivert.com/blog/2008/01/euler-005/Problem 005:
object Euler5 extends Application { val divisors = List(20, 19, 18, 17, 16, 15, 14, 13, 12, 11); def check (value :Int) :Int = { if (divisors.exists((a) => (value % a != 0))) return check(20+value) else return value } println(check(20)); } Interestingly the tail recursive version above runs in ~1500ms whereas this iterative version takes ~37000ms:
object Euler5 extends Application { val divisors = List(20, 19, 18, 17, 16, 15, 14, 13, 12, 11); def notDivisible (value :Int) :Boolean = { return divisors.Euler 006
http://samskivert.com/blog/2008/01/euler-006/
Wed, 09 Jan 2008 00:00:00 +0000http://samskivert.com/blog/2008/01/euler-006/Problem 006:
object Euler6 extends Application { val first100sum = List.range(1,101).foldLeft(0)(_+_); val first100sumsq = List.range(1,101).foldLeft(0)((b, a) => (b + a*a)); println(first100sum * first100sum - first100sumsq); }Euler 007
http://samskivert.com/blog/2008/01/euler-007/
Wed, 09 Jan 2008 00:00:00 +0000http://samskivert.com/blog/2008/01/euler-007/Problem 007:
object Euler7 extends Application { var numbers = List.range(2,110000); var primes = List(2); while (primes.length < 10001) { val prime = primes.head; numbers = numbers.filter((b) => (b%prime != 0)); primes = numbers.head :: primes; } println(primes.head); } My numbering system encouraged the incorporation of a certain British Secret Service Agent into my solution, but imagination failed me.Euler 008
http://samskivert.com/blog/2008/01/euler-008/
Wed, 09 Jan 2008 00:00:00 +0000http://samskivert.com/blog/2008/01/euler-008/Problem 008:
object Euler8 extends Application { val number = ("73167176531330624919225119674426574742355349194934" + "96983520312774506326239578318016984801869478851843" + "85861560789112949495459501737958331952853208805511" + "12540698747158523863050715693290963295227443043557" + "66896648950445244523161731856403098711121722383113" + "62229893423380308135336276614282806444486645238749" + "30358907296290491560440772390713810515859307960866" + "70172427121883998797908792274921901699720888093776" + "65727333001053367881220235421809751254540594752243" + "52584907711670556013604839586446706324415722155397" + "53697817977846174064955149290862569321978468622482" + "83972241375657056057490261407972968652414535100474" + "82166370484403199890008895243450658541227588666881" + "16427171479924442928230863465674813919123162824586" + "17866458359124566529476545682848912883142607690042" + "24219022671055626321111109370544217506941658960408" + "07198403850962455444362981230987879927244284909188" + "84580156166097919133875499200524063689912560717606" + "05886116467109405077541002256983155200055935729725" + "71636269561882670428252483600823257530420752963450"); val WINDOW = 5; def prod5 (offset :Int) :Int = { number.slice(offset, offset+WINDOW).toList.map((c) => (c - '0')).foldLeft(1)(_*_) } println(List.range(0, number.length-WINDOW).foldRight(0)((o, g) => (Math.Burning Map
http://samskivert.com/blog/2007/09/burning-map/
Mon, 17 Sep 2007 00:00:00 +0000http://samskivert.com/blog/2007/09/burning-map/My friend Chad sent me an awesome image of Burning Man, so I located myself on the map for all the world to see:
Click the image for larger versions of the image and for the full photo. Web Client Development
http://samskivert.com/blog/2007/09/web-client-development/
Thu, 06 Sep 2007 00:00:00 +0000http://samskivert.com/blog/2007/09/web-client-development/I gave a presentation at the Austin Games Conference with Michael Grundvig on the subject of using web technologies to create clients for MMOs and other multiplayer online games. The slides, for interested or insomniac parties, are available in PDF form. The Great Rosenfeld
http://samskivert.com/blog/2007/06/the-great-rosenfeld/
Sun, 17 Jun 2007 00:00:00 +0000http://samskivert.com/blog/2007/06/the-great-rosenfeld/I pitched in on a madcap effort to create a film in 48 Hours over this weekend which was absurdly fun, not least because our genre was Superhero, which necessitated running around dressed in ridiculous costumes.
Thanks to the miracle of YouTube, you can see the fruits of our labor:
And Hillary took a bunch of awesome pictures along the way. Cowboys versus Ninjas versus Whirlpools
http://samskivert.com/blog/2007/03/cowboys-versus-ninjas-versus-whirlpools/
Sun, 11 Mar 2007 00:00:00 +0000http://samskivert.com/blog/2007/03/cowboys-versus-ninjas-versus-whirlpools/Daniel and I gave a talk at the GDC again this year (well, Daniel gave about half a dozen of them, but I don’t share his enthusiasm for public speaking). We divulged the juicy details on OOO’s financial performance, Bang!’s early metrics and gave a demo of our new project Whirled. Have a look at the slides if you go for that sort of thing. iConcertCal
http://samskivert.com/blog/2007/02/iconcertcal/
Sat, 03 Feb 2007 00:00:00 +0000http://samskivert.com/blog/2007/02/iconcertcal/This thing is so awesome! It’s a plugin for iTunes (a visualizer) that scans your music library and then looks for upcoming shows by anyone whose music you own. Within seconds of installing it, I found out about four great shows that I would have never thought to look for. I didn’t even have to tell it I was in San Francisco. It magically figured that out from my IP address.Shipped It!
http://samskivert.com/blog/2006/12/shipped-it/
Wed, 06 Dec 2006 00:00:00 +0000http://samskivert.com/blog/2006/12/shipped-it/After almost two years of taking enthusiastic liberties with the themes of the Wild West, we’ve finally shipped Bang! Howdy. Since it’s an online game this doesn’t mean something wonderful like we’re done working on it, just that we have to be more careful when we ship new features as a bunch of people will be annoyed if we break anything. But it is nice to be reminded of why it is that we toil long and hard when we see people playing and enjoying the game.Scala
http://samskivert.com/blog/2006/08/scala/
Sun, 06 Aug 2006 00:00:00 +0000http://samskivert.com/blog/2006/08/scala/Scala has piqued my interest more than any language to come down the pike in a long time. Type inference makes me cry out with joy, Java-compatibility, sensible mix-in support (made all the more useful by their very sophisticated type system), first-class functions, continuations (mostly), very SML-like type pattern matching, list comprehensions. One could get into some serious trouble with this language.
I was then even more excited when I saw a paper by the language designer describing how he was able to easily implement an elegant stackless threads system as a library using only the functionality provided by the language (and the small compromise of requiring a continuation passing style, but the elegance of the language construct being used makes that hardly noticable).Bang! Howdy Pardner
http://samskivert.com/blog/2006/03/bang-howdy-pardner/
Sat, 25 Mar 2006 00:00:00 +0000http://samskivert.com/blog/2006/03/bang-howdy-pardner/I finally put up screenshots on the Bang! Howdy website, ain’t they purdy:
Daniel and I also gave a talk about Bang and Yohoho at the GDC. I’ll get the slides up for that shortly. A new way to remap your keys
http://samskivert.com/blog/2005/07/a-new-way-to-remap-your-keys/
Fri, 15 Jul 2005 00:00:00 +0000http://samskivert.com/blog/2005/07/a-new-way-to-remap-your-keys/This keyboard is mind-bogglingly cool. Where has the decade gone?
http://samskivert.com/blog/2005/03/where-has-the-decade-gone/
Tue, 22 Mar 2005 00:00:00 +0000http://samskivert.com/blog/2005/03/where-has-the-decade-gone/While making non-narcissistic use of the Wayback Machine, I couldn’t resist finding out what it had to say about go2net, an Internet company for which I must admittedly take a certain responsibility. They go as far back as December 1996, the proverbial damned long time ago.
How we managed to go from jabbering about a wacky idea in a brew pub in San Diego to fully operational Internet site with five major products in little more than five months still boggles my mind — though it does lend credence to my bitching about working “18 hours a day, 7 days a week”.GDC 2005
http://samskivert.com/blog/2005/03/gdc-2005/
Sun, 13 Mar 2005 00:00:00 +0000http://samskivert.com/blog/2005/03/gdc-2005/I surived another GDC. Daniel and I gave a presentation on Puzzle Pirates, the slides for which are available for perusal. There are lots of pretty pictures and graphs in there, but the words alas disappeared into the ether after we spoke them. The Burning Down the House talk was inspiring, but it didn’t usurp my all-time favorite GDC talk, Professor Moriarty’s Secret of Psalm 46, given back in 2001.Gardening for Fun
http://samskivert.com/blog/2005/03/gardening-for-fun/
Sat, 12 Mar 2005 00:00:00 +0000http://samskivert.com/blog/2005/03/gardening-for-fun/The proverbial side project has emerged to see the light of day: http://www.gamegardens.com/.The Centiscopic World
http://samskivert.com/blog/2005/02/the-centiscopic-world/
Mon, 07 Feb 2005 00:00:00 +0000http://samskivert.com/blog/2005/02/the-centiscopic-world/I finally dug out and plugged in this Intel Play microscope that I picked up on a lark a while back. At 200x it’s damned near impossible to adjust the cheap plastic platform in increments small enough to get good focus and without decent lighting, it’s hard to get a good image, but it is pretty neat. After looking at the collection of dog hair and honeybee wings they included in the box, I looked around for something else to jam under there.Favorite Games of 2004
http://samskivert.com/blog/2005/01/favorite-games-of-2004/
Wed, 05 Jan 2005 00:00:00 +0000http://samskivert.com/blog/2005/01/favorite-games-of-2004/The games I enjoyed playing most this year (in some vague order of enjoyment quotient):
Pikmin 2 – GC Paper Mario – GC 塊魂 [Katamari Damacy] – PS2 Sly 2 – PS2 Hot Shots Golf: Fore! – PS2 I also played a few wacky indy games that I really enjoyed:
Samorost – Flash Zep’s Dreamland – Vinders N – Flash As I generally don’t review games that I don’t finish, it may be hard to gauge what I played based on my somewhat sporadic review output.I ate the purple berries…
http://samskivert.com/blog/2004/09/i-ate-the-purple-berries/
Wed, 08 Sep 2004 00:00:00 +0000http://samskivert.com/blog/2004/09/i-ate-the-purple-berries/Yes kids, it was that time of year again, the time when we gather up our craziest costumes, dream up projects with no practical value and spend a week in the desert doing our best to help everyone else have a good time. It’s a bird, it’s a plane, it’s Burning Man!People creating interesting works right now
http://samskivert.com/blog/2004/08/people-creating-interesting-works-right-now/
Sun, 08 Aug 2004 00:00:00 +0000http://samskivert.com/blog/2004/08/people-creating-interesting-works-right-now/I was recently thinking about how the sum total of people in history who had the ability to create works of art that might impact my life compares to the sum total of people alive today that have the ability to create works of art that might impact my life. I think the former is indeed a much smaller group and yet they are so much more well known. Thus I decided that I should do my part to spread the word about people that I think are achieving greatness in this very day and age.A soft, rich and beautiful fabric
http://samskivert.com/blog/2004/08/a-soft-rich-and-beautiful-fabric/
Wed, 04 Aug 2004 00:00:00 +0000http://samskivert.com/blog/2004/08/a-soft-rich-and-beautiful-fabric/There is a huge billboard in Shibuya with a digital display counting down to this inscrutable EXPO thing, the nature of which remained a mystery to me until now.
Leave it to Japan to blow untold quantities of cash on something so touchy feely as giving everyone a “global perspective” to work toward solving the environmental problems that have reared their ugly heads during the 20th century. Indeed, more likely the insatiable construction industry in Japan ran out of places to erect new buildings in Tokyo and needed something to satisfy their craving for government funds.アボカドの和
http://samskivert.com/blog/2004/07/%e3%82%a2%e3%83%9c%e3%82%ab%e3%83%89%e3%81%ae%e5%92%8c/
Tue, 13 Jul 2004 00:00:00 +0000http://samskivert.com/blog/2004/07/%e3%82%a2%e3%83%9c%e3%82%ab%e3%83%89%e3%81%ae%e5%92%8c/Through some deeply fortunate happenstance of international shipping, the avocados at my local supermarket arrive daily with a ripeness so sublime as to bring a tear to your eye. My relationship to avocados in their native California was one of frustration. Invariably, I would bring home an inedibly firm specimen and resolve to remember to make use of it during the short window one or two days hence when it would achieve peak deliciosity, only to suffer a bout of culinary neglect that left me scraping the oxidized brown chunks from the edible remains and resolving to strengthen my resolve the next time.Random bitching
http://samskivert.com/blog/2004/07/random-bitching/
Wed, 07 Jul 2004 00:00:00 +0000http://samskivert.com/blog/2004/07/random-bitching/What kind of error message is this?
[11:20pm] baltic:~ java -jar foo.jar Exception in thread "main" java.util.zip.ZipException: No such file or directory at java.util.zip.ZipFile.open(Native Method) at java.util.zip.ZipFile.(ZipFile.java:112) at java.util.jar.JarFile.(JarFile.java:127) at java.util.jar.JarFile.(JarFile.java:65) It doesn’t even tell me what file or directory is missing. You might think it’s obvious because I just ran the command, but frequently java is run from a shell script and all I see is this baffling crap about zip files.二番目の印
http://samskivert.com/blog/2004/06/%e4%ba%8c%e7%95%aa%e7%9b%ae%e3%81%ae%e5%8d%b0/
Sun, 06 Jun 2004 00:00:00 +0000http://samskivert.com/blog/2004/06/%e4%ba%8c%e7%95%aa%e7%9b%ae%e3%81%ae%e5%8d%b0/I wish Mark Twain would have studied Japanese so that I could read his keen insights on how it could be made more scrutable to native English speakers.Fucking Japanese (Language)
http://samskivert.com/blog/2004/06/fucking-japanese/
Wed, 02 Jun 2004 00:00:00 +0000http://samskivert.com/blog/2004/06/fucking-japanese/So my friend writes in an email: どうしてかって？ A reasonably innocuous statement, except I’m not exactly sure which verb かって is. So I consult my trusty dictionary:
欠く (かく) (v5k) to lack; to break; to crack; to chip; (P);
書く (かく) (v5k) to write; (P);
掻く (かく) (v5k) (1) (uk) to scratch; (2) to perspire; (3) to shovel; to paddle; (P);
描く (かく) (v5k) to draw; to paint; to sketch; to depict; to describe;The terrorists have already won the browser wars
http://samskivert.com/blog/2004/06/the-terrorists-have-already-won-the-browser-wars/
Wed, 02 Jun 2004 00:00:00 +0000http://samskivert.com/blog/2004/06/the-terrorists-have-already-won-the-browser-wars/I ask myself why it’s not trivially easy for me to share bookmarks between browsers on the same and different machines, why I can’t even share my remembered password database between various incarnations of Mozilla on the same machine, why my addressbook is a scattered mess of overlapping collections in any number of incompatible formats. How have these basic needs been going unmet for now well over a decade?
Is it because the many eyes of open source are focused on esoteric bullshit like platform independent, declarative, XML-based user interface specification languages and the ability to skin everything from my word processor down to the dock applet that displays the network traffic going in and out of my machine?女の太鼓
http://samskivert.com/blog/2004/05/%e5%a5%b3%e3%81%ae%e5%a4%aa%e9%bc%93/
Sun, 16 May 2004 00:00:00 +0000http://samskivert.com/blog/2004/05/%e5%a5%b3%e3%81%ae%e5%a4%aa%e9%bc%93/We happened upon this all women taiko drumming group at Yoyogi park, maybe as part of some massive celabratory business in Tokyo this weekend called the Sanja Matsuri or maybe they just like to show off their big drum. Regardless of their motives, I was impressed.I 愛 Hatsudai
http://samskivert.com/blog/2004/05/i-hatsudai/
Sat, 08 May 2004 00:00:00 +0000http://samskivert.com/blog/2004/05/i-hatsudai/Have I mentioned how much I love my neighborhood? The kids walking home from school are always blurting out funny things. There are lots of old people sitting around on benches smiling. The station is five minutes away. They are even so kind as to put up banners everywhere expressing my feelings to the world in my native language. What a great place!Oh Mom, not temples again!
http://samskivert.com/blog/2004/05/oh-mom-not-temples-again/
Wed, 05 May 2004 00:00:00 +0000http://samskivert.com/blog/2004/05/oh-mom-not-temples-again/I recently learned how to complain about something in Japanese (お寺なんて、なん回も見に行ったよ), so I thought I’d celebrate with yet another temple picture. This one being in the middle of Tokyo and thus easy to get to assuming two million Tokyoites aren’t making the rounds at the time.Yaks!
http://samskivert.com/blog/2004/05/yaks/
Mon, 03 May 2004 00:00:00 +0000http://samskivert.com/blog/2004/05/yaks/This is one of my many new bovine friends from Nepal. The whole story is even available for those of you with too much time on your hands or an uncommonly keen interest in mountain mammals.咲きましょう！
http://samskivert.com/blog/2004/04/%e5%92%b2%e3%81%8d%e3%81%be%e3%81%97%e3%82%87%e3%81%86%ef%bc%81/
Sat, 03 Apr 2004 00:00:00 +0000http://samskivert.com/blog/2004/04/%e5%92%b2%e3%81%8d%e3%81%be%e3%81%97%e3%82%87%e3%81%86%ef%bc%81/My new apartment came with its very own set of sakura and they are simply lovely.
I’ll refrain from gushing about how much better my new place is than my old one. Quality of life has vastly improved.Cavorting in Kamakura (鎌倉)
http://samskivert.com/blog/2004/03/cavorting-in-kamakura/
Sat, 20 Mar 2004 00:00:00 +0000http://samskivert.com/blog/2004/03/cavorting-in-kamakura/Another fascinating weekend trip has been photo-documented for your mildly vicarious pleasure. Fate brings us this time to the time worn hamlet on the coast of central Japan that they call Kamakura.お酒 anyone?
http://samskivert.com/blog/2004/02/anyone/
Sat, 28 Feb 2004 00:00:00 +0000http://samskivert.com/blog/2004/02/anyone/I was wandering through Yoyogi park and came upon this massive wall of sake casks. The sign explaining them was filled with 分からない漢字 so I have no idea why it was there, but it looked cool.そんな体をカイリのは
http://samskivert.com/blog/2004/02/%e3%81%9d%e3%82%93%e3%81%aa%e4%bd%93%e3%82%92%e3%82%ab%e3%82%a4%e3%83%aa%e3%81%ae%e3%81%af/
Fri, 20 Feb 2004 00:00:00 +0000http://samskivert.com/blog/2004/02/%e3%81%9d%e3%82%93%e3%81%aa%e4%bd%93%e3%82%92%e3%82%ab%e3%82%a4%e3%83%aa%e3%81%ae%e3%81%af/As my local supermarket is on my way home from school, I actually go there about twice a week — a vast improvement from my San Francisco schedule which was more like once every two months.
For the last four weeks or so, next to the checkout stands, a little TV has been playing this ad for a new drink. Over, and over, and over again. The ad isn’t more than twenty seconds long and it’s a catchy little tune sung while a man with a little frog hat on hops up some stairs.Meandering up Mitake-san
http://samskivert.com/blog/2004/02/meandering-up-mitake-san/
Thu, 12 Feb 2004 00:00:00 +0000http://samskivert.com/blog/2004/02/meandering-up-mitake-san/One of my friends invited me on a little excursion up a mountain not too far outside of Tokyo. Since my mother has been pestering me for pictures of Japan, I’ll go ahead and share them with the whole class.Clever spammers
http://samskivert.com/blog/2004/02/clever-spammers/
Mon, 09 Feb 2004 00:00:00 +0000http://samskivert.com/blog/2004/02/clever-spammers/I happened to notice there were comments on some of my posts. Rather surprised that anyone I knew would bother to spend words on this solipsistic enterprise, I curiously investigated. I was right in a totally unexpected way. Spammers are apparently now posting to blogs with semantically ambiguous content, presumably in hopes that people will click on the link provided to the “poster’s” home page. They leave no stone unturned.Gnomespotting in Ebisu
http://samskivert.com/blog/2004/02/gnomespotting-in-ebisu/
Sun, 01 Feb 2004 00:00:00 +0000http://samskivert.com/blog/2004/02/gnomespotting-in-ebisu/iMac rebranded for Japanese audience
http://samskivert.com/blog/2004/01/imac-rebranded-for-japanese-audience/
Wed, 21 Jan 2004 00:00:00 +0000http://samskivert.com/blog/2004/01/imac-rebranded-for-japanese-audience/Fratricide!
http://samskivert.com/blog/2004/01/fratricide/
Sat, 17 Jan 2004 00:00:00 +0000http://samskivert.com/blog/2004/01/fratricide/Cute as he may be, the little chicken mascot on my Nissin ramen package seems to be making dastardly work of his unborn little brother. He does look pretty happy about the whole business. Perhaps he’s relieved that he won’t have to vie for mommy’s attention.
Unrelatedly, it snowed today! I haven’t been sprinkled with those falling flakes in a mighty long time. Alas it’s unlikely that I’ll be dreaming of a white Tokyo.ヨガ
http://samskivert.com/blog/2004/01/%e3%83%a8%e3%82%ac/
Sat, 17 Jan 2004 00:00:00 +0000http://samskivert.com/blog/2004/01/%e3%83%a8%e3%82%ac/I went to my first yoga class today. How fascinating it was to reverse engineer the instructor’s running commentary from only a knowledge of the grammatical structure and the things we were supposed to be doing with our bodies. I learned so many new nouns and verbs! I did get a little lost when he started talking about India and energy flow but at least I now know how tell people to bring their gaze to their nose in Japanese.Zoom zip!
http://samskivert.com/blog/2004/01/zoom-zip/
Fri, 16 Jan 2004 00:00:00 +0000http://samskivert.com/blog/2004/01/zoom-zip/I’m not sure how things are elsewhere in Asia, but in Japan, people ride their bikes on the sidewalks at very high speeds. Not a day passes when I don’t have a near-fatal collision with a speeding bicyclist on my way to class. The sidewalks are crowded with people, mind you. I have a hard enough time not bumping into other pedestrians without the zooming chariots of death screaming by periodically.Flippy flippy
http://samskivert.com/blog/2004/01/flippy-flippy/
Sun, 11 Jan 2004 00:00:00 +0000http://samskivert.com/blog/2004/01/flippy-flippy/Nearly every store clerk from whom I’ve had the pleasure of receiving change in bills has done this really cool flippy thing where they swing the bills around with their pinky and snap them one by one in a very blatant counting process. It’s like Vegas!
I’ll have to find out if that’s part of the job training or if it’s just something one learns in the wily course of adolescence.ゴジラxモスラxメカゴジラ 東京SOS
http://samskivert.com/blog/2004/01/xx-sos/
Sat, 10 Jan 2004 00:00:00 +0000http://samskivert.com/blog/2004/01/xx-sos/You might think that campy, low-tech special effect having Godzilla movies were relegated to the land of cult following. But you’d be wrong. Second only to Finding Nemo in screen count is this cinematic masterpiece: Godzilla vs. Mothra vs. Mecha-Godzilla: Tokyo S.O.S.
I bet my meager Japanese skills won’t even stand in the way of my enjoyment of this film. La langue du cinéma est universelle.Savage Beasts!
http://samskivert.com/blog/2004/01/savage-beasts/
Mon, 05 Jan 2004 00:00:00 +0000http://samskivert.com/blog/2004/01/savage-beasts/In perusing the text of my new lease, I couldn’t help but dwell on this particular subsection:
3. When using Object, Borrower must not do what are written below.
To produce or possess firearms, swords, explosive or ignitable substances. To bring in or fix up heavy and large equipment such as a large-scaled safe. To use TV, stereo set and other appliances at full blast and to play the instrument such as piano.Automatic!
http://samskivert.com/blog/2004/01/automatic/
Sun, 04 Jan 2004 00:00:00 +0000http://samskivert.com/blog/2004/01/automatic/There’s simply a lot more automation going on in this country. Automatic doors abound. My toilet activates some sort of fan when I close the lid, but only if I’ve actually used it. It can tell. Even the little clock built into the bed in my hotel room detects when there’s been no motion in the room and dims its LCD display so as to provide a more soothing sleeping environment.Joining the club
http://samskivert.com/blog/2004/01/joining-the-club/
Thu, 01 Jan 2004 00:00:00 +0000http://samskivert.com/blog/2004/01/joining-the-club/I can’t say that I have a strong feeling about blogs one way or the other. I had a short lived fling with LiveJournal, but we parted ways amicably many months back as I was feeling guilty for being so neglectful.
Given the arrival of the New Year and my own arrival in Tokyo just two days past, I figured it was time to rekindle the flame with self-indulgence, lacking style and banal commentary.Tokyo NYE
http://samskivert.com/blog/2004/01/tokyo-nye/
Thu, 01 Jan 2004 00:00:00 +0000http://samskivert.com/blog/2004/01/tokyo-nye/Having arrived in Tokyo but 36 hours before year’s end, I felt something of a sense of urgency with regard to my New Year’s Eve plans. Forunately, the Tokyo club scene is even better documented (via the Internet) than San Francisco.
A few minute’s perusal turned up the Jungle Calendar and a promising party in my vicinity at a club called Aoyama Hachi. Another couple of hours of research left me with a vastly better grasp on the nightlife resources at my disposal, but with nary a better alternative than my first lucky find.