106 karma · joined December 14, 2008
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;
} pairs = (>>= \ ~(x:xs) -> map ((,) x) xs) . init . tails
EDIT: Or as a list comprehension: pairs xs = concat [map ((,) h) t | (h:t) <- tails xs]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.
fibs = fix $ (1 :) . scanl (+) 1My 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 :)
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.
http://www.ted.com/talks/aimee_mullins_prosthetic_aesthetics...
http://www.ted.com/index.php/talks/aimee_mullins_on_running....
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.
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).
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.
Part 1: http://www.youtube.com/watch?v=DagVklB4VHQ&feature=relat...
Part 2: http://www.youtube.com/watch?v=UjKciefHo38&feature=relat...
For example, I recently needed to do some Run-Length Encoding:
import Control.Arrow
import Data.List
encodeRLE :: (Eq a) => [a] -> [(Int, a)]
encodeRLE = map (length &&& head) . group
decodeRLE :: [(Int, a)] -> [a]
decodeRLE = concatMap (uncurry replicate)