Archive for March, 2008

Preserving your OpenAFS installation when switching IP addresses

March 30, 2008

About a week ago during spring break, I actually got OpenAFS running on an old computer that someone gave to me. There are two parts to the configuration, the client and the server. Getting the installation to properly run on the server was a challenge, but it worked. The client on the actual server was working, however when I tried to make it work with another separate computer, it totally crapped out. After a long waiting period in an IRC chatroom, it was noted that I had my /etc/hosts file totally wrong, and the file is not the same for the client and the server. For future reference, this is what the file needs to look like:


127.0.0.1                localhost
your.static.ip.addr      hostname.network.ext

I was on a private network, so I just used ecks-net.priv for the network.ext string. However, whenever I used the vos listvldb command, it was showing me wrong output. Even when I fixed my /etc/hosts file it was showing the incorrect IP address. Apperently OpenAFS keeps a database of the server’s ip address taken from /etc/hosts upon initialization of the software, and keeps that in there no matter if you change your /etc/hosts file or IP address. If something like that happens, or for some reason the client registers the incorrect ip address, this is what you will need to do at the server:


vos syncvldb -server `hostname`  -verbose -localauth
vos syncserv -server `hostname`  -verbose -localauth
vos changeaddr localhost -remove -local
vos listaddr -nore
/etc/init.d/bos shutdown
cd /var/lib/openafs/DB
rm vldb.DB0 vldb.DBSYS1
cd /var/lib/openafs
rm sysid sysid.old
cd /var/log/openafs
rm *
/etc/init.d/openafs-server start
vos listvldb
vos syncvldb `hostname` -local- verbose
vos listvldb

Your vldb should now contain the correct hostname. What we did is we deleted the database file, then regenerated it back again. Here is a reference to the actual IRC log, you can track down the conversation by looking for the “noecksit” string. This is very useful when you change your static IP address and have to reconfigure OpenAFS with the new IP address.

Advertisements

A tic-tac-toe implementation using haskell

March 30, 2008

After about half a year, I can finally say that I am comfortable using haskell as a language. Dealing with the functional part, the biggest stumbling block for me were the Data types, just because you cannot declare Data types in other languages as you do in haskell. In languages like Java or Python you can’t really really declare your own Data types. You can create classes, but that is different since they may not be just containers, they may change the outside world somehow. In haskell, a Data type is just that, a container, kind of like a slot for some value. That value may be restricted to a certain subset, or it may be a special kind of slot (for instance, a tree), but it cannot be executed to change some state outside of itself. The other thing that I haven’t seen before anywhere else is the use of higher-order functions, and mainly being able to pass a function as a parameter to another function. I have never seen this property in math either, but I’m sure it exists, I just haven’t taken such advanced courses yet. That leads me to my topic, which is an AI agent for a tic-tac-toe implementation that I made using haskell. It is available at hackage if anyone wants to try it out. I used two references when I was coding the project, Principles of Artificial Intelligence by Nils Nilsson, and the paper Why Functional Programming Matters by John Hughes. Both of these were excellent references, especially the paper. The program makes extensive use of higher-order functions and function composition. It uses minimax and alpha-beta pruning for its algorithm. Using these functions, I could test out certain functionalities one by one. What I used to do before in imperative languages was print statements, which would get very messy. Here I can just test the input of a function, and as long as it returns the desired output for all my tests, I don’t have to worry about that function at all. That lets me concentrate on one problem, without thinking about other functions introducing some errors. I also used maps and zips in a nice way. I first made a function that given a board, returns a list of all the possibilities of that board, calling it moves. After that, I made a recursive function reptree that in this case takes moves (a function!) as parameter, and a Tree with only one root, mainly the board that we wanted to pass into moves. The reptree function constructs another tree with the board as root, and since the children of the root is a list, it maps reptree moves over the list generated by moves called with the root board as parameter. Therefore, it becomes a recursive function that given a certain board as parameter, can generate a tree of all the possible possibilities ever to occur! OK, that however generates only the board moves, what I really want the actual values of the moves. Therefore I have a function getValue, that for a certain board, outputs a number and that’s all it does. How it actually generates this number is explained in the comments of the source code. All I do then is map the function getValue over the tree that I generated and I get as output a tree of the values. I can then just simply feed that output to maximise which would return to me the most advantageous value. One thing that the paper doesn’t mention and something I didn’t find anywhere is how to get the actual board, since you get a value from maximise but you can’t really do anything with it, all it tells you is the value of the best move, but the actual move is lost. Therefore, I just made a tree zipper that zips the two trees together and returns a tree of tuples consisting of the value and the actual board. We then feed the tuple to maximise, with it only looking at the first value, but actually returning a tuple of the value and the best move. That gives you a best move that the agent should make some time in the future however, considering both the player and the enemy play optimally. We need the best move right for the next move that we need to make, not the move a couple of plies down the line. It’s good thing that I provide a list of history that tells us what moves the board has already generated, so I just backtrack to one move after the current move and I have my best move for the next ply. My code is still not as pretty as I would like it to be, due to a couple of hacks I had to make, but it is a lot better than what I would have had to go through if I wrote this in an imperative language.