Evil Science A whole load of stuff

20Jan/140

7 tricks to simplify your programs with LINQ

Does what it says above. Very handy.

http://igoro.com/archive/7-tricks-to-simplify-your-programs-with-linq/

Filed under: C# No Comments
8Jan/142

Creating a RogueLike Game View with C#

In a RogueLike the game view (GV) is a rectangular area of the map occupied by the player that is displayed on screen, an example of which is shown below. A gameview consists of two parts: a size and an origin (the x and y coordinates which define the top left corner). The origin is calculated from the player's current coordinates by subtracting half the GV width from player X and half the GV height from player Y, and making adjustments to them under certain conditions described below.

gameview1

This article describes how to calculate the coordinates required for a game view.

Terminology

The following terms are required in order to calculate the GV origin coordinates GVOriginX and GVOriginY:

  1. PlayerX, PlayerY - The coordinates of the player's current location
  2. GVWidth, GVHeight ?- The size of the game view
  3. MapWidth, MapHeight - The size of the map the player is exploring.

It is assumed that MapWidth > GVWidth and MapHeight > GVHeight.

For the player to be displayed dead centre in the GV GVWidth and GVHeight must be odd numbers.

Calculations

This origin of the GV is defined as:

  • GVOriginX = playerX - GVWidth / 2
  • GVOriginY = playerY - GVHeight / 2

Therefore, the bottom right corners coordinates of the GV are GVOriginX + GVWidth and GVOriginY + GVHeight.

However, there are obvious conditions where GVOriginX and / or GVOriginY are less than 0, or the bottom right coordinates exceed the MapHeight and / or MapWidth, so we need to make the followings checks and correct as appropriate after calculating generating GVOriginX and GVOriginY:

Check Correction if true
GVOriginX < 0 GVOriginX = 0
GVOriginY < 0 GVOriginY = 0
GVOriginX + GVWidth > MapWidth GVOriginX -= (GVOriginX + iViewWidth - MapWidth)
GVOriginY + GWHeigtht > MapHeight GVOriginY -= (GVOriginY + iViewHeight - MapHeight)

The effect of making these changes will cause the player to be displayed off centre and closer to the edge being moved towards, as shown below. If none of the above corrections are required, the player will be shown in centre of GV as shown in the picture at the start of this article.

gameview2

Code

A Visual Studio demonstrating the above method in a simple demo which allows a player to explore a map using the keys Q,W,E,A,S,D,Z,X and C can be found here.

Github: here.

Have I seen this before?

The observant amongst you will notice that this code comes from my Evil Science article?Field of Vision using recursive shadow casting: C# .Net 3.5 implementation, but I thought I'd use the code again with emphasis on how to draw the Game View.

Filed under: C#, Roguelike 2 Comments
6Jan/146

Simple Roguelike Dungeon Generator Using C#

Building a dungeon for your character to explore, along with being able to see that dungeon, ?is one of the most important parts of a Roguelike, and unlike sight algorithms there is a near infinite number of ways that a dungeon can be generated.?This article describes a simple map building algorithm using rooms and corridors, which is written in C# 3.5 - links to the code are the bottom of this article.

Building a Map

Using the app is pretty simple: select one of the two options in the combobox in the top left corner and click the button Build and a map will be generated. The property grid on the left hand side can be used to adjust various map building properties, which are discussed in more detail below.

MapBuilder

Two options are offered for building a map:

  1. Build_OneStartRoom - a start room is placed in the centre of a map as starting point, and rooms and corridors are built of it.
  2. Build_ConnectedStartRooms - two rooms are placed on opposite sides of the room and joined with a corridor?as starting point, and rooms and corridors are built of it.

The difference between the two methods is that Build_OneStartRoom()?produces a map with rooms and corridors clustered together, whilst Build_ConnectedStartRooms?produces a more distributed map that fills more of the map area.

Map Properties

Adjusting the properties, which are discussed in more detail below, can produce maps with different appearances. Here are a few examples:

Example1
Build Probability: 100 - this will cause corridors to only be built of existing corridors.
Example2
Build Probability: 0 - this will cause corridors to only be built of existing existing rooms.
Example3
Rooms to Build: 5 and Maximum Corridor Turns: 25. Nice twisty corridors!
Example4
Corridor Spacing: 10, Break Out: 1000. Corridors must be a distance of 10 units away from other corridors. Break Out counter is increased?to allow successful map generation.

 

Map Building Logic

Both of the map building options use the following logic to build a map:

  1. Place start room or rooms.
  2. Required number of rooms built? No, go to step 2, else quit.
  3. Get a random point on the edge of a room, or a corridor,
  4. Test if the only point is valid. Yes, go to step 3, else step 1.
  5. Attempt to build a corridor and examine the outcome of that method:
    1. The corridor has hit an existing room: build corridor
    2. The corridor has hit an existing corridor: build corridor.
    3. The corridor operation has completed: attempt to build a room on the end point of the corridor, and if successful build the corridor.
  6. If?break out?property exceeded exit the loop. Prevents the loop from getting stuck.
  7. Go to step 1.

Properties

Mapbuilder has a number of properties which can be adjusted to determine the appearance of the generated map:

  1. Corridor Related
    1. Corridor Spacing - the number of empty cells the corridor has to have on either side of it for it to be built. This is dependant upon the direction it is travelling. If travelling north, it must have that number of empty cells to the east and west of it.
    2. Minimum Length - the minimum length of a corridor.
    3. Maximum Length - the maximum length of a corridor.
    4. Maximum Turns - the maximum number of direction changes a corridor can make whilst it is being built.
  2. Map
    1. Map Size - the size of the rectangle containing the dungeon.
    2. Break Out - When this value is exceeded, exit the dungeon generating While loop.
  3. Probability
    1. Select room - the value between 1 and 100, that when exceeded will cause a room to be selected as the starting point for a corridor build operation.
  4. Room
    1. Corridor Distance - the minimum distance a room can be placed from existing corridors.
    2. Distance from other rooms - the minimum distance a room can be from other rooms before it can be built.
    3. Maximum Size - the maximum size of a room.
    4. Minimum Size - the minimum size of a room.
    5. Rooms to build - the total number of rooms to build.

Corridor Building

The process for finding a start point for a corridor is:

  1. To randomly choose a start point on a corridor or room and a direction the corridor will "grow" in using the method?Corridor_GetStart. The property?Select Room is used to determine the probability of choosing a corridor or room, by default it is set to 50%.
  2. If step 1 successful pass the start point and direction the method?CorridorMake_Straight and examine the return value to determine what to build, some of the return values are:
    1. Completed: corridor has been completed without running into anything.
    2. Hit existing corridor: corridor has hit an existing corridor.
    3. Hit existing room
    4. Hit self

(All return types are described in the enum?CorridorItemHit).

In the example method Build_ConnectedStartRooms()?and Build_OneStartRoom(), if the corridor is completed, an attempt to build a room of it is made and if that is successful both the room and corridor are built. If the corridor hits an existing room, an existing corridor or itself the corridor is built.

Corridors are added to the map array, and also stored in the generic list?lBuilltCorridors to enable additional tests when attempting to build other rooms or corridors. When a corridor is being built it is stored in the generic list?lPotentialCorridor.

Room Building

A room is a rectangle which is built of a corridor end point in the direction the corridor was moving. After a rectangle has been created using the properties?Minimum Size?and?Maximum Size, it is tested in the method Room_Verify()??for the following:

  1. Check it occupies legal, empty coordinates in the map 2d array.
  2. It is expanded by the property?RoomDistance and tested to see if it makes contact with any current rooms stored in the generic list?rctBuiltRooms.
  3. It is expanded by the property CorrdiorDistance?and tested to see if it makes contact with any current rooms stored in the generic list?lBuilltCorridors?.

If the above criteria are met, the room is built - it is added to the 2d array map, and the rectangle which defines it is added to the?generic list?rctBuiltRooms.

Directions

When a corridor is being built a direction is chosen using one of the two methods:

  1. Direction_Get(Point dir) - get a random direction, as long as that direction is not the opposite of the one provided to the method. This prevents back tracking.
  2. Direction_Get(Point pDir, Point pDirExclude) -??get a random direction, as long as that direction is not the opposite of the one provided to the method AND the direction specified in?pDirExclude. The later direction is the first direction chosen when a corridor is built - this will stop a generating corridor from going in the opposite direction to the one ?it started with. Makes longer, less twisty corridors.

The corridor building method?CorridorMake_Straight () offers a parameter called?PreventBackTracking,?that when set to to true will select the later option and when false the former. In all build_ examples, a value is selected randomly.

Break out, or getting stuck

Adjusting the properties will produce mazes with different characteristics, but may cause prevent the map from being built, for example if one specifies 100 rooms in a relatively small map the loop contained within the build method will never exit as 100 rooms won't fit, so a counter is placed within the loop that will cause the loop to exit when the property?Break Out?is exceeded?and the method will return false and in the provided application a messagebox will alert the user to this.

The Map Builder Code

The class?csMapbuilder.cs?contains the code used to build a map.

The public methods?Build_ConnectedStartRooms() and?Build_OneStartRoom() are called to build a map, and the boolean value returned indicates if building a map was successful; success occurs when the required number of rooms are built before the property?Break Out is exceeded.

The public property Map, a two dimensional integer array contains the built map. A value of 1 indicates a solid cell and value of 0 is an empty space your adventurer can explore.

Here's a bit of pseudo code demonstrating the above:


csMapbuilder mpbuild?= new csMapbuilder(150, 150); //the numbers are the starting map size

if (mpbuild.Build_ConnectedStartRooms() == true)
{

//map drawing code to go here
}

Get the code

To download the C# source code click here.

Github: click here.

Filed under: Main 6 Comments
6Jan/140

Island and labyrinth generating algorithm using C#

This is a simple generating routine I developed in C# whilst experimenting whilst playing around with the algorithms for?Conway's Game of Life.By adjusting the properties it can produce "island" or "labyrinth " type maps.?I "discovered" this algorithm

Here's a few examples of maps it can generate, with the property values used to create them.??Explanations of the properties are given later in the article.

default.png
x=100,y=100,p=45, h=true, n=4, i = 50000 produce an "island" map.
variant1.png
?x=100,y=100,p=45, h=false, n=4, i = 50000 produce a "labyrinth" map.
variant2.PNG
 x=100,y=100,p=55, h=true, n=4, i = 50000.
variant3.PNG
 x=100,y=100,p=45, h=true, n=4, i = 85000.
variant5.PNG
x=100,y=100,p=45, h=false, n=2, i = 50000.
variant6.PNG
 x=100,y=100,p=75, h=true, n=5, i = 80000.

Using the App

Load up the app, fiddle with the properties and click the?Go button.

How it Works

Map generation is controlled by the following variables:

  1. p (int) - close cell probability. Between 0 and 100.
  2. h (bool) - cell operation specifier.
  3. i (int) - counter.
  4. n (int) - number of cell's neighbours.
  5. c (int) - examined cell's closed neighbours. Between 0 and 8.

Calling the method go() in the class csIslandMaze?will generate a map using the following logic:

  1. Randomly choose a cell from map
  2. If the cell is open use a p to determine whether we close it.
  3. Get c
    1. h = true: If c > n close the cell, else open it.
    2. h = false: If c > n open the cell, else close it.
  4. Repeat steps1 - 3 i number of times.

Varying the above mentioned variables will produce maps of surprisingly different appearances.

Source Code

You can download the C# source code here.

Github: here.

Filed under: C#, Roguelike No Comments
24Dec/135

Field of Vision using recursive shadow casting: C# .Net 3.5 implementation

A working field-of-view ?(FOV) algorithm is one of the essential parts in any roguelike, it is used to calculate which mapcells, within a given radius, that can be seen by seen by the player. This article describes a C# implementation of such an algorithm, known as recursive shadow casting which is described in more detail in the article ?FOV using recursive shadowcasting - improved.

Shadow Casting

Shadowcasting divides the FOV calculations into eight octants and visits the ?mapcells of each ?row by row or column by column, starting with the nearest row or column and working it's way outward.

  ------>  6 row 6 last
   ----->  5 .
    ---->  4 .
     --->  3 .
      -->  2 row 2 second
       ->  1 row 1 is scanned first
        @  @ this is the starting point

When a scan comes across a cell that blocks the players line of sight it calculates which other cells in rows/columns farther away that isn't visible because of the blocker. Those cells are "in shadow", hence the term shadowcasting.

  -...---  - = visible cells
   -..---  # = blocking cell
    -#---  . = cells in blocker's shadow
     ----
      ---
       --
        @

The above text is taken from this article, from the website RogueBasin. I have shamelessly lifted this text, as I feel it is a very clear description of how shadowcasting works, and I can't improve upon it.

The Application

Below are several pictures of the application which demonstrate that algorithm.?The lighter squares represent the cells visible to the player, and the darker ones are those which the player cannot see.?The maze displayed in the map has been generated using another algorithm (which I'll post soon) and is loaded when the application starts up.

fov2 fov3

The keys q,w,e,a,d,z,x and c control the player move the player. W is up, S down, d right, A left right etc

Source Code

The source code can be downloaded?here.?And to run it, you'll need Microsoft Visual Studio which you can find here.

Github: the code for the class FOVRecurse.

What's Going On?

The class FOVRecurse.cs?contains the FOV algorithm, and the?methods are GetVisibleCells and ScanOctant are where the magic happens.

When the player moves, the method GetVisibleCells?is called which in turn calls the method ScanOctant for each of the?8 areas surrounding the player and?all the cells that the player can see are stored in a generic list. Upon completion of this scan the the event?playerMoved is fired, which causes the map to be redrawn in the form event?pictureBox1_Paint.

There really isn't that much to say about it as the code speaks for itself, but if you're stuck with anything please add a comment and I'll get back to you.

Acknowledgements

This post takes text from the RogueBasin articles:

  1. FOV using recursive shadowcasting - improved.
  2. FOV using recursive shadowcasting

I have used the take from the above as I feel these are the best explanations of how the shadow casting technique works, and I can't really improve upon them.

Filed under: C#, Roguelike 5 Comments
20Dec/131

Sudoku Brute – a C# implementation of the Brute-force algorithm

The brute force algorithm is "dumb" method of solving a sudoku puzzle: it sequentially tries a potential solution for an unsolved cell and then moves onto the next and attempts to find a solution for that cell, and upon finding one will move onto the next and if a solution is not found, it steps back to the previous solved cell, selects a new solution and moves onto the next again. By doing this over and over, it can be guaranteed to find a solution for any valid sudoku puzzle. However, this can be time consuming with some of the more complex puzzles taking several minutes to solve.

I have written a C# application which implements the?brute-force algorithm?to solve Sudoku puzzles. It's written using .Net 3.5 in Visual Studio 2008, and offers two different implementations of the brute-force algorithm - one uses arrays to hold data and the other using Linq to manipulate classes which hold data.?Practically, they both use the same algorithm, just different methods of implementation. From my limited testing, they both take the same time to produce a solution for any grid; the inclusion of both was just me trying different technologies.

The app is pictured below and?comes with fifty examples and allows one to add and save sudoku grids, and modify existing ones. To view an animated gif of the brute in action click here.

sb

It's ?straight forwards to use and is controlled through the toolbar, whose functions left to right, are as follows:

  1. New sudoku
  2. Load a saved sudoku
  3. Save an existing sudoku
  4. Solved the current sudoku
  5. Reload the current sudoku
  6. Stop a solution attempt
  7. Display screen updates - selecting yes will display the solution process in real time. Selecting this option will slow down the solution process.

In addition, there are two radio buttons allowing one to select the solution class - either a Linq or array based method.

Downloads

To download the executable and sample solutions, click here.

To download the source files and solutions, click here. To view the source code and run it, you'll need Microsoft Visual Studio which you can find here.

Use the above code at your own risk, and I accept no liability for any harm that may come to their computer.

I always enjoy feedback, so if you have any comments or suggestions, please leave a comment below

Filed under: C# 1 Comment
22Nov/131

And I’m back…

...did you miss me? of course you didn't, as nobody reads what I post or visits this site. Hey ho.

A while back, WordPress was giving me an error when I tried to hit the site, saying a file, wp-db.php, was missing. I ignored it for a while, and then it started to depress so I set about fixing it. I wasn't really sure what to do, and after spending some time examining the error logs I worked out the aforementioned file was missing, so I downloaded the latest version of WordPress, acquired an FTP Client and uploaded the missing file.

Great success!

Filed under: Main 1 Comment
5Sep/131

C#/.NET Fundamentals: Choosing the Right Collection Class

This is a link to an excellent article about the classes available for managing object collections.

http://www.blackrabbitcoder.net/archive/2011/06/16/c.net-fundamentals-choosing-the-right-collection-class.aspx

Filed under: C# 1 Comment
4Sep/130

Use LINQ to calculate the Greatest Common Factor of a fraction

Want to calculate the Greatest Common Factor of fraction? Use this handy piece of LINQ:

int denom = 12;
int num = 8;
int gcf = Enumerable.Range(2, num - 1).LastOrDefault(i => num % i == 0 &amp; denom % i == 0);

//gcf == 4

It returns a value of 0 if a GCF isn't found, hence the LastOrDefault.

It's straightforwards enough I think.

Filed under: C#, Project Euler No Comments
4Sep/130

Calculate the divisors of a number

Here are two different ways of calculating the divisors of a number using C#, something you're going to find extremely helpful when tackling Project Euler.

This method uses a for loop and a generic list.

static List<int> GetDivisors(int n)
{
    List<int> div = new List<int>();
    div.Add(n);
    for (int ctr = n / 2; ctr > 0; ctr--)
        if (n % ctr == 0)
            div.Add(ctr);

    return div;
}

This one uses an Enumerable Range and LINQ, and returns the results as a generic list.


int n = 6556;
List<int> div =
Enumerable.Range(1, n / 2).Where(i => n % i == 0).Union(new List<int>{n}).ToList();

//returns 48 results

Enjoy.

Filed under: C#, Project Euler No Comments