HN user

FalconNL

106 karma
Posts0
Comments25
View on HN
No posts found.

The wording on question 9 (the regex one) is a little unclear: both b[l].e and ([^b]b[^b]*){3} will match blabber but not babel. Presumably the intended meaning is that the entire string must be matched, but the question does not make this explicit.

The last time I made a world generation algorithm for a voxel engine prototype I got reasonable results through the judicious combination of different types of noise, (specifically simplex, ridged and turbulence noise) and transforming the result using cubic hermite splines for added control, provided you are okay with generally only having one or two main continents (three and four do occur, but are much less common).

This image shows 16 possible world maps (I found it useful to just have them appear next to each other in the world so I could quickly get an overview of the consequences of tweaking parameters): http://imgur.com/dthr7O2

This is the algorithm that generated the world (written in C#). permutation is a random ordering of the numbers 0 to 255, repeated twice. HermitePoints take an x and y coordinate and a slope. Noise functions take an x and y coordinate, a number of octaves, a frequency and a permutation. Turbulence and ridged noise output results in the domain [0, 1], simplex noise in the domain [-1, 1].

  private static Chunk GenerateChunk(short chunkX, short chunkZ, int seed, byte[] permutation)
  {
      var chunk = new Chunk(chunkX, chunkZ);

      int worldMapSize = 256;
      short maxHeight = (short)Math.Min(worldMapSize >> 2, Chunk.CHUNK_HEIGHT);

      float[] worley = new float[2];

      HermiteSpline continentCurve = new HermiteSpline(new[]
      {
          new HermitePoint(0f, 0f, 0f), new HermitePoint(0.07f, 0.03f, 1f), new HermitePoint(0.12f, 0.1f, 0.7f),
          new HermitePoint(0.21f, 0.18f, 1f), new HermitePoint(0.24f, 0.2455f, 0f), new HermitePoint(0.26f, 0.26f, 1f), new HermitePoint(1f, 1f, 1f)
      });
      HermiteSpline continentMask = new HermiteSpline(new[]
      {
          new HermitePoint(0f, 0f, 0f), new HermitePoint(0.25f, 0f, 0f), new HermitePoint(0.4f, 1f, 0f), new HermitePoint(1f, 1f, 0f)
      });
      HermiteSpline plateMountainCurve = new HermiteSpline(new[]
      {
          new HermitePoint(0f, 0f, 0f), new HermitePoint(1f, 1f, 3.5f)
      });

      for (short x = 0; x < Chunk.CHUNK_SIZE; x++)
      {
          for (short z = 0; z < Chunk.CHUNK_SIZE; z++)
          {
              int globalX = (chunkX << Chunk.CHUNK_SIZE_LOG2) + x;
              int globalZ = (chunkZ << Chunk.CHUNK_SIZE_LOG2) + z;

              //Subdive the world into squares, each of which contains an independent world map
              //The edges of each square are lowered so that each map is separated by oceans
              float xSeparator = (float)Math.Sin((globalX & (worldMapSize - 1)) * MathHelper.Pi / worldMapSize);
              float zSeparator = (float)Math.Sin((globalZ & (worldMapSize - 1)) * MathHelper.Pi / worldMapSize);
              float rectSeparator = (float)Math.Min(1, 3 * Math.Min(xSeparator, zSeparator));
              float circleSeparator = xSeparator * zSeparator;
              float mapSeparator = rectSeparator * 0.375f + circleSeparator * 0.575f + 0.05f;

              //Use turbulence noise to get the typical clumped shape of continents and add some simplex and ridged noise for the thinner shapes
              float continentNoise1 = Noise.Turbulence(globalX, globalZ, 8, worldMapSize, permutation);
              float continentNoise2 = Noise.Simplex(globalX, globalZ, 8, worldMapSize * 0.16f, permutation) * 0.5f + 0.5f;
              float continentNoise3 = Noise.Ridged(globalX, globalZ, 8, worldMapSize * 0.5f, permutation);
              continentNoise2 *= continentNoise2;
              continentNoise3 *= continentNoise3;
              float continentHeight = continentNoise1 * 0.5f + continentNoise2 * 0.25f + continentNoise3 * 0.125f;
              float baseHeight = continentCurve.Map(continentHeight * mapSeparator);

              //Add mountains caused by convergent continental plate boundaries
              float continentMult = continentMask.Map(baseHeight);
              float plateMountainNoise1 = Noise.Ridged(globalX, globalZ, 8, worldMapSize * 0.4f, permutation);
              float plateMountainNoise2 = Noise.Simplex(globalX, globalZ, 8, worldMapSize * 0.2f, permutation) * 0.5f + 0.5f;
              float plateMountainNoise = plateMountainNoise1 * 0.66f + plateMountainNoise2 * 0.33f;
              float plateMountainHeight = plateMountainCurve.Map(plateMountainNoise) * continentMult;

              //Apply the map separation
              float finalHeight = baseHeight + plateMountainHeight;

              //Convert the height from range [0,1] to range [1,255]
              byte height = (byte)(finalHeight * (maxHeight - 1) + 1);

              for (short y = 0; y < height; y++)
              {
                  chunk[(short)x, y, z] = (byte)((y + 1) * 255 / (maxHeight + 1));
                  chunk.SetStack((short)x, z, new short[] { height, (short)(Chunk.CHUNK_HEIGHT - height) });
              }
          }
      }

      return chunk;
  }

There's no need for XML, nor for all-white video. A 32x32 icon of some color noise, stored as PNG, GIF, or BMP, takes about 2-3 KB. Writing an algorithm to procedurally generate a vaguely interesting video and music can easily be done in less than that. Check out the demoscene for numerous examples. Naturally not all videos can be generated this way, but his statement is still true.

And yet another short, functional solution:

    pairs = (>>= \ ~(x:xs) -> map ((,) x) xs) . init . tails
EDIT: Or as a list comprehension:
    pairs xs = concat [map ((,) h) t | (h:t) <- tails xs]

I don't know if this will add much to the article, but let's go over things step by step.

scanl is the same as foldl, save for the fact that it outputs a list of all intermediate values. So where

    foldl (+) 0 [1..10]
would output 55,
    scanl (+) 0 [1..10]
would output [0,1,3,6,10,15,21,28,36,45,55].

(1 :) means prepend a 1 to the list it is given. The function that is passed as an argument to fix therefore returns a 1 followed by the successive summation values of its argument.

fix just infinitely applies its argument to itself, i.e.

    fix f = f (fix f)
In any strict language this would ofcourse just result in an infinite loop, but fortunately Haskell has lazy evaluation. So if we evaluate the list, for example with
    take 5 fibs
the following happens:

Haskell wants the first list element. The first element of (1 :) . scanl (+) 1 is 1, so there's no need to evaluate the scanl part yet. Now we need the second element. scanl first returns its accumulator, so that's another 1. For the third list element scanl needs the first element of its argument for the addition, so now we get to the recursive application. As before, the first element of (1 :) . scanl (+) 1 is 1, so the next element is 1 + 1 = 2. This 2 is then added to the next element, which is another 1, resulting in 3. Finally, we add 3 to the third element, giving 5. We now have five elements, which is what we requested, so the result will be [1,1,2,3,5].

I hope this helped a little. If you have any other questions, just let me know.

As an alternative to the zipWith method of calculating the Fibonacci series, you can use scanl, resulting in (in my opinion) an even more elegant version:

    fibs = fix $ (1 :) . scanl (+) 1

$40? As long as Joss and the original cast are on board I'll happily pay $100, maybe even $200, even if it's only another half season. Just promise not to start this project before Castle has stopped being good, since I love Nathan in that as well.

The Beauty of LaTeX 16 years ago

Alternatively, for those who want good-looking text but prefer the WYSIWIG approach: just use a half-decent DTP program like InDesign, which will get you everything mentioned in the article except for the per-character transparency.

Interestingly, if you multiply 15 years by 365 days and the two hours a day mentioned at some point in the article, you get 10,950 hours, which is remarkably close to Malcolm Gladwell's claim from the book Outliers that it takes 10,000 hours to become a superstar at something.

I've tried it a bit, but I found the syntax rather ugly compared to Haskell. I know, I'm nitpicking and it really shouldn't matter that much, but it put me off the language. Perhaps when they finally release a full-blown implementation of F# for Visual Studio I'll give it another go. My main reason for still using C# at the moment is the UI integration with WPF and Windows Forms. Ideally there'd be an actively maintained Haskell.NET, but perhaps F# can serve as a compromise when Visual Studio 2010 comes out.

No, I mostly make a new one per project. All the functions are pretty much one-liners anyway, so it's not too much work to make. It's more of a documentation thing; anything in Haskell.cs can be assumed to work exactly the same as its Haskell equivalent.

I can't comment on Lisp, but I've been working with Haskell for about a year or so now, so I'll cover that instead.

My personal history goes something like QBasic -> Visual Basic -> PHP -> Java -> C# -> Haskell.

Since Haskell is a purely functional language there's no cheating like you could in, say, OCaml. This forces you to learn how to work with immutability, which I have become a big fan of. When working with C# I try to avoid mutability as much as possible (naturally this is quite a bit uglier than in Haskell, but it does avoid some problems). Most of my C# projects now acquire a Haskell.cs file fairly quickly, containing things like a Tuple class, zip, >>=, etc.

In the time I've spent learning it, Haskell has quickly become my favourite language. It's not perfect (my current main wishes are existential types and an extensible record system), but it is considerably less painful than the other languages I know.

As for speeding up the transition, I can't offer anything other than just diving in. At some point it will just click and you will wonder what all the commotion is about (another monad tutorial? why?). Granted, I still don't have the slightest idea about why I would want to use a hylomorphism or what to do with a comonad, but perhaps I will some day. Fortunately you don't need them in everyday Haskell programming :)

Not so much obsession as convention. Generally versions 0.x - 1.0 are the alpha and beta releases, with 1.0 being the first "stable" release. Obviously there are hundreds of projects that follow a different schema, but it's used enough that it has stuck. One solution if you want to keep your versioning style would be to annotate them as stable or development, possibly with a short paragraph explaining that version 0.0.3 is in fact bugfree/feature-complete/ready for use in production/etc.

Very nice site, thanks.

In case anyone from Grooveshark is reading this, here are two minor UI suggestions:

- It's rather easy to miss the volume control since it's so far removed from the other play controls. Perhaps it would be an idea to move it over there.

- A button to queue up all the songs in a search result. If it exists already I'm not seeing it.

"Never ascribe to malice, that which can be explained by incompetence."

I must say it's getting really hard to tell the difference in this case.

"less is being paid for than ever before." Really? The second the first recording company came into business it was making 18 billion a year? I'm fairly sure it's still higher than throughout most of the history of the recording industry.

"Unfortunately The Pirate Bay does what it says in its description and its main aim is to make available unauthorized material." No, its main aim is to facilitate the sharing of files. The users choose to upload illegal material.

"It is common sense, if they couldn’t get it for free they would buy it and when we ask them, they confirm that." Prove it. I download plenty of music to see if it's any good, sometimes via youtube, sometimes via torrents. Probably at least 95% isn't, so I delete it again. I certainly wouldn't buy it.

"When asked if downloaders have less money than others, Kennedy said that younger people have the money but just don’t spend it on music anymore. Kennedy said that the reduction in sales in the music industry is directly attributable to illegal downloading." Again, PROVE IT. I suspect that if you put music sales next to video game sales you'll see some very close correlation between the decline of the former and the rise of the latter.

"He was asked if he understood BitTorrent. [...] It was very clear he knew nothing about any remotely technical issues." Perhaps you could spend 10 minutes reading up on it so you know what you're talking about in a court of law?

"The reason for this drop is that the number of premieres have increased but sales have decreased. File-sharing has somewhat made the market thinner." Or maybe people have only a limited budget for movies, so now they have to split it between them, resulting in lower sales per movie? Or you just make too many crappy movies? Again, get some proof.

"Sandgren further told that the damages they claim are based on a fictitious license fee." So basically they're just pulling numbers out of their ass.

"He had to admit, however, that he has no evidence to back these claims up." I'm not even going to comment on this one.

If only I were the judge... I'd hold them in contempt of the court for wasting everyone's time with unsubstantiated BS. Or better yet, sue the entertainment industry because they cost me several billion dollars. How did I arrive at that figure? Well, I have no evidence to back that claim up, but it seems reasonable to me. Now give me my money.

Pathetic.

From what I understand you're supposed to get the result (in your example 6) by combining the cells in that box with the given operator (in this case times).

So a "6x" box with two cells results in (1 and 6) or (2 and 3), since those are the only products that result in 6. Likewise, "7+" with three squares can only be (1, 2 and 4).

Indeed. Though there are some fairly easy steps to reduce this as much as possible.

1. Give guests full use of all the features of the site. Posting, editing, befriending, etc. Store this information by identifying them by the combination of IP + username (which they have to enter for each post) or something similar. This will encourage them to participate (no barrier to entry) and let them decide whether or not they want to become a full member.

2. If they register, link everything they posted while they were guests to the new account, i.e. change the username on all the old posts (if necessary), etc. That way they don't lose all their stuff.

3. The only required information should be a username and password. An e-mail address should be optional, with a warning that if you don't provide one you won't be able to recover your account if you lose your login details. Naturally you should be able to provide one later if you decide you really don't want to lose the account. This keeps the "You just want to send me spam" people happy.

4. No mandatory confirmation email. When you click submit on the registration form you should be logged in and ready to go. Opening your mail client/website is an unnecessary and annoying step.

I might have missed one or two points, but adhering to these rules should take the majority of the pain out of registering.