Monday, May 31, 2010

New Version

The easiest column to write each month is this one. I describe the great features of the latest version of Forge. This version has 259 new cards, which means that it supports a grand total of 3,220 cards. All of the credit goes to Dennis, Chris, Slapshot5, Jim, Snacko, and others who have contributed making Forge the outstanding program that it is today.

There is a lot of new stuff. Now the quest mode has another other option, you can either choose “Realistic” or “Fantasy”. Realistic is the old quest mode where you win cards and can buy cards from the card shop. The fantasy option is similar to an RPG because you build up your stats.

The fantasy mode features a “bazaar” where you can buy upgrades for your character including: buying various creatures that you have at the beginning of each game, buying more life (because you start out with 15 but you can have more than 20), or buying a free mulligan (you mulligan and you draw 7 cards). After 25 wins various other “quests” open up for you that feature harder AI opponents. For a taste of the new fantasy quest mode unzip Forge, click on the “Quest Mode” button, and then click on the “Continue Quest” button.

Another cool feature for both quest modes is that each computer opponent now has a small picture next to its life points. Even though this is just a small change, it really improves the “fun level” since the computer opponents vary from Abraham Lincoln to Lisa Simpson.


Forge is all about the cards, so let me list a few of the new ones. A few cards from Rise of the Eldrazi, like the huge artifacts Artisan of Kozilek and Ulamog's Crusher as well as the level up creature Kargan Dragonlord, Valakut, the Molten Pinnacle and the classic Mana Vault which helps you accelerate your mana.

05-16 Forge (9 MB) - Requires Java and runs on Windows, Mac, Linux, etc... This is the 05-16 version because that is when it was released on the forums.

Download Pictures (78 MB) - The card pictures can be downloaded by the Forge program or you can just grab this file. This includes most but not all of the pictures, it doesn't have the newest 259 card pictures.

Have a great Memorial Day! Cookouts for everybody!!

p.s.
The fantasy mode has one more rule that I want to explain. Usually there is a 500 credit limit for cards that you sell but that limit is removed after you win 50 games. (The correction is that you have to win 50 times, my mistake.)

Wednesday, May 26, 2010

How Forge Processes the Mouse - most boring post ever

(This is probably my least exciting article ever. Processing the mouse is very important but very boring. This post is more likely to be interesting to people who want to write a program like Forge.)

Handling the mouse can become very complicated since a "mouse click" can do many different actions depending on the context: choose targets for a spell or ability, advance to the next phase, or is used to declare attacking creatures. Forge uses the state pattern to process all of the mouse input. Without the state pattern I have no idea what I would have done. I think it works well but it can be tricky to understand.

Below is the Input class that handles the mouse. To better understand the Input class let me briefly explain how Forge implements different phases. Each phase extends Input and shows the name of the phase to the user through showMessage(). Usually a phase will let a user do a specific action like the Main phases allow the user to play any type of card or a land. MainInput.selectCard() handles the processing of playing a card or land.

Input class is also used whenever a spell or ability needs to choose a target. The Input for Shock would use showMessage() to show the user a message like "Select target creature or player to receive 2 damage." If the player clicks on a card, selectCard() checks to see is that card a creature. If the user clicks on a player, selectPlayer() is called.
class Input
{
//showMessage() is always the first method called
public void showMessage()
public void selectCard(Card c, PlayerZone zone)
public void selectPlayer(String player)
public void selectButtonOK()
public void selectButtonCancel()
}
There are a few details that I have left out. First, how does an Input tell the rest of the program that it is done and the next Input should be processed? Forge handles all of the Inputs using a stack and the Input class has a method called stop() which just pops the stack. Second, how do the phases advance? I just hardcoded them, nothing fancy. Main 1 always advances to "Before Declare Attackers". When the Main 1 Input method selectButtonOK() is called, it pops itself and pushes the next Input onto the stack.

Since the method showMessage() is always the first method called, I can put code in there that I would usually put into a constructor. Another trick that I do with showMessage() relates to planeswalkers. Forge was written before planeswalkers were added to Magic so it didn't have the concept of "you can only use one of these abilities once a turn" or loyalty counters but I used showMessage() to fake it. I won't show you the code since it is very crufty and hacked-together even by my standards. Where there is a will, there is a way. :--)

Random quote, “Time is a great teacher, but unfortunately it kills all its pupils.”

p.s.
I lied when I said that "Forge handles all of the Inputs like a stack". In reality Forge doesn't stack inputs. It has a stack but it is only one deep. This can be seen if you play two legendary creatures that have an effect when they go to the graveyard like Keiga, the Tide Star. If you play a 2nd Keiga, you only get to steal one creature. And knowing is half the battle. (Yes, I pretend to be funny even though I'm not.)

p.p.s.
The Input class is also used for mulligans.

Monday, May 24, 2010

Coding with Java and Forge

(This article is only about programming but I don't want to discourage non-programmers from reading it too.)

Transmuting an idea into words can be difficult. (Hey, you have to give me extra credit for using a Magic keyword.) The concept is that Forge's cards are technically in Java but cards must also use the Forge framework. If you only know Java, you won't understand how Forge encodes cards. You have to understand how Forge does things.

Let me throw a quote at you from my favorite book Code Complete. This is talking about high-level code that is written in terms of the problem domain, "Code at this level won't depend much on the specific features of your programming language because you'll have built your own set of tools to work with the problem. Consequently, at this level your code depends more on the tools you've built than on the capabilities of the language you're using."

The idea of using an existing framework usually appears in bigger projects but JUnit is a good example of a smaller program. A framework tries to be "easy for someone else to learn" even though it takes time to really understand the framework. There is a ton of interesting Java libraries but many of them have a steep learning curve. I haven't touched the physics library JBox2d because it seems so complicated. (I want to use JBox2d to program a free version of Fantastic Contraption. I don’t want to ripoff their artwork but maybe I could copy their style?) fantasticcontraption.com

OK, back to Magic. When I was writing Forge I didn't realize that I was writing a framework that combined Java and Magic. Somewhere after I wrote a few cards it hit me that Forge's framework isn't very flexible and there are some cards that it would never support. This is always a scary time because part of you wants to start over and do it better but I forged ahead anyways. ("Forged ahead", I'm a really funny guy, I think.)

The tricky thing when writing a framework is that you don't really know all of its limitations. One day you may think, "Forge will never support Glorious Anthem" but then later you (or someone else) comes up with a nifty little hack and voila, you're using Glorious Anthem in your white weenie deck. You have to use a framework for awhile in order to really understand its limits.

Forge's framework is pretty good. There are obviously some rough spots but overall it works "good enough."

p.s.
Code Complete goes on to say that your high level "code should be somewhat readable by someone who's not a computer-science whiz". Forge tries but doesn't quite get a gold star. Although at least 2 people have learned Java just so they could work on Forge, so at least I did a decent job on the framework. Frequently frameworks come with external documentation so you don't have to understand the details of the code in order to use it. This is the Holy Grail of programming, code reuse.

Writing code that someone can understand is hard. Writing a framework (much longer code) that someone else can understand is much harder.

Monday, May 17, 2010

Forge's Awesome AI

It's been awhile since I've talked about "Forge's awesome AI". Basically Forge's AI is very simple. Each spell and ability has a method called canPlayAI() which returns true if the AI should play it. Royal Assassin's ability is a good example. The AI for Royal Assassin's activated ability checks to see if you have any tapped creatures and then targets the biggest one. Shock does about the same thing, except that the code tries to kill X/2 flyers and 3/1 creatures and avoids plain 2/2.

The biggest flaw of canPlayAI() is that each card and ability is evaluated separately. The computer will never use two Shocks to kill a 4/4. Since each card is evaluated individually it is hard to create decks that the AI can use effectively. Generally the AI is good with creatures and basic, aggro decks. One of the decks that I submitted as a deck for the quest AI had all vampire creatures, it did not include any sorceries or instants. Some of the vampires had effects that trigger when you play them, which acted like sorceries. The AI could use the deck because it only had to play creatures and then attack.

Combat is handled completely separate. The attacking code tries to be aggressive and will usually attack. Sometimes the AI should attack but is too cautious, thus causing the game to stretch out. (I tried to avoid problem of when the AI would attack with everything and then you would attack and win but I accidentally caused this "stalling" problem.)

The blocking code is also very simple. The AI tries to make decent blocking decisions. The blocking code is more complicated than the attacking code since you can have multiple blockers and generally you don't want flyers to block non-flyers.

The attacking and blocking code does not do anything fancy and just uses a "for" loop to generate which creatures will attack or block. Let me explain the "for" loop for the attacking code. The code looks at each of the computer's creatures individually and asks, "Should this creature attack?" The blocking code does to the same thing, it looks at each attacking creature and asks, "Should this creature be blocked?"

Obviously this isn't how a human player attacks or blocks. Players, like myself, attack or block based on the whole combat situation, all of the creatures. So the AI does very little processing when it comes to combat and that explains why it makes so many mistakes in that area. Ideally the AI would do a CPU intensive search to generate better combat decisions.

Forge's biggest snafu is that the AI doesn't play spells during your turn, except for counterspells, or during combat. This was done to simple the code for canPlayAI(). Coding canPlayAI() for "normal" situations is hard, so coding for unusual situations (like other phases) is out of the question.

The biggest strength of Forge's AI is that it plays by the rules, nothing fancy. On paper it sounds easy until you begin coding and then you start pulling you hair out. Making the AI use the same resolve code as the player is very hard. (Forge's early design dictated that I had to code each card twice. One for the player and one of the computer. I knew this was the wrong way to go.)

For awhile Wagic's AI couldn't use activated abilities and I knew exactly how hard I worked on that. (Unfortunately it is hard to help someone because different projects have different UML designs, how everything fits together.)

p.s.
By the way, Wagic is a great project. It has more cards than Forge and a nice user interface. Shoutouts to wololo. (The guy who started Wagic.)

p.p.s.
And as a side issue, Forge still uses the "old combat" rules.

Wednesday, May 12, 2010

Open Source Project - Part 2

Dennis sort of organically took over the project. I never asked him to and he never asked could he, he just did it. Open source projects can become heated debates and anybody can "fork" and start their own project. All you have to do is download the source code and then say, "I wish it had a dancing, purple bear in the background" and voila, you have just forked a project. Forking is generally bad because it splits people's time, which is your most valuable resource, since people are only volunteering their time anyways.

Honestly, the Forge project has been very successful and fulfilling. Now I'm just the "old guy" that started the project and doesn't contribute much these days. Dennis, Rob, and others have "found my vision" and enjoy coding Magic. After awhile programming Magic becomes sort of a "meta-videogame" because coding itself seems like a game because you are constantly challenging yourself.

HuggyBaby and GoblinKing have provided Forge's forum which allows for more interaction between the users and the guys who do the programming. Without the forums, Forge would be a lesser program. The forums is also where "us" developers chat and ask each other questions like, "What in tar-nations does the stupid Input class do?".

(The Input class is handles all mouse input and it can be confusing. I started the forum topic "How to understand the Input class in 4 hours or less". I'm joking about the 4 hours part but I still wrote a thorough explanation.)

And last but not least, you the readers (and downloaders) have made Forge special. Forge was written because I had an itch but other people seem to have the same itch too. I'm also the first to admit that Forge is far from perfect but it is still very fun. I play Forge so much, I have a hard time thinking, "What if Forge never existed?"

p.s.
The Incantus magic project which allows people to play Magic with rules enforcement over the Internet has recently gone "open source". Incantus is written in Python and has a wonderful user interface. The rules enforcement is so good that is probably can implement 95% of all Magic cards in existence.

Incantus Project
Incantus Forum

The Wagic project, which lets you play against the computer and was written for the PSP but can also be run on Windows, is written in C++ and is also open source.

Wagic Project
Screenshots

And I hate to leave anybody out. MagicWars lets people play over the Internet like Incantus and is written in Java. Currently it has 719 cards.

MagicWars Project

Monday, May 10, 2010

Open Source Project - Part 1

Making a program "open source" means that you allow the world the chance to download and peek-and-poke around your source code. (Having someone look at your source code is also very personal because it is easy to criticize someone else's code.) The advantage of this method is that maybe, just maybe you can recruit other people to help do some of the programming. This has happened with Forge. Forge started out as a one man project but now it has 5 or so active programmers.

By the way the current "lead developer" is Dennis and he is a great leader. He donates the most time and I admire his dedication. He also doesn't complain about my code, so he is a good guy in my book. :--)

Most open source project are just lumps of source code lying around with no documentation. Many projects never end up producing any code at all, they are just ideas that never get written, see SourceForge. Now don't get me wrong, there are also lots of productive, useful programs on SourceForge. Writing a program that someone else can use is actually very hard. (And if you wondering if I stole Forge's name from SourceForge, the answer is probably. I didn't sit down and try to think of a name, I just let my fingers type something and Forge just appeared.)

When I say that most open source projects are lump of code lying around with no docs, I mean it. Forge was the same way. Forge's saving grace was that it actually did something, so people could see it in action and get excited and want to contribute code. If a program doesn't do anything, people aren't going to get excited. Showing me some UML is great and all that but UML and other documentation is deadly boring. I mean people would rather hit themselves in the head with a rubber hammer than read UML or specifications. (UML is just line drawings which show how the major parts of a program fit together.)

Another good attribute of Forge is that the program is fun to use. It isn't a boring report generator; it is an actual, fun, interesting videogame. Yes, some people probably love working on the Linux or Apache but they aren't what most people would consider fun.

And truthfully I didn't think anyone else would ever take a second look at Forge's source code. Yes I'm the world 2nd greatest programmer and all that but why would someone actually slog through and read my code? And don't forget, Forge has no documentation. Yes, I tried to give objects and methods good names but it is still hard to figure out what a 500 line object does even if all of the methods are well named.

Open source software also has the "side effect" of being free which makes it popular. :)

Friday, May 7, 2010

Rise of the Eldrazi - High Quality Scans

Magic has wonderful card art. These are high quality scans from the CCGHQ team. They are trying to scan every Magic card printed, including all variations and promos, which is a huge task. They have a forum here.

Rise of the Eldrazi - 37 MB, includes tokens and "tips and tricks" cards

Thursday, May 6, 2010

New Version

(I am only 35 or so hours late. I should never predict when I’m going to do something.)

Forge now has 115 new cards, which brings the grand total to 2,961 cards. All of the credit goes to DennisBergkamp, RobCashwalker, Chris H, Jim, and slapshot5. Thank you for your work.

OK, the good stuff, the cards. Forge now supports unearth and has 11 cards with that keyword including: Hellspark Elemental (1R, 3/1, trample haste, sacrifice at EOT) and lets you attack again for 1R with unearth. Dregscape Zombie is a generic 2/1 that costs 1B but "Unearth: B" gives the card some depth.

A bunch of lands were added. City of Brass produces any color of mana but also deals damage to you. Exotic Orchard is quirky land that depends on the lands that you opponent has. Reflecting Pool is similar but it depends on the lands that YOU control, basically it clones one of your lands.

Some older cards include: Copper Tablet, 2, artifact, which deals 1 damage to each player during their upkeep, sort of a clock of doom. The Rack, 1, artifact which punishes your opponent for having more than 3 cards, combine this with Howling Mine and force you opponent to draw cards with Ancestral Recall for maximum damage. The land Diamond Valley "tap: Sacrifice a creature: You gain life equal to the sacrificed creature's toughness." And the enchantment Karma which punishes your opponent for using Swamps.

AND, I almost forgot, Quest now has a Card Shop for added variety. The quest mode is the best way to play against the computer, oh the thrill of victory! :)

Forge has a ton of just fun cards like the green morphing Thornling which has 5 activated abilities or Isochron Scepter that lets you abuse any cheap instant or the artifact Time Vault which lets you skip a turn now for an extra turn later.

In the deck editor if you want to look at the new cards, click on the "Sort By" menu and select "Newer cards first". (I know that sounds a little weird but I didn't know what to call it.) Sometimes a card will be redone as a keyword, so while the card isn't strictly new, its implementation is new. (Some cards are created at runtime using special keywords that represent spells and abilities. Look at Exotic Orchard, Shock, or Vithian Stinger in cards.txt for more info.)

Forge 04-10 Version (8 MB) - 04-10 is when it was released on the forums.

Download Pictures
(78 MB) - The card pictures can be downloaded by the Forge program or you can just grab this file.

Monday, May 3, 2010

How Good Is Java?

I wrote Forge using Java for mainly one reason: I know Java very well. I've worked with Java for a number of years and I enjoy it. Using Java has resulted in a few positive consequences such as Forge being portable and able to run on Linux and Mac which probably accounts for roughly 5-10% of the downloads. People from both communities seem excited to play Magic. Magic knows no boundaries, not even operating systems, ha.

I was worried that people might not have Java installed on their computer. While this may be a problem a small percentage of the time, most people seem to already have Java. Part of me really hates requiring users to download extra libraries like Java. I honestly thought about programming Forge in C++ because it wouldn't require any extra libraries.

(I personally see Java as a cleaner C++. Java seems to be at the same level of abstraction as C++ since both languages make it hard to pass a function to a function, so called higher order functions. And technically yes you can do it in C++, Java, and even in C if you want to but it is very messy.)

Java isn't perfect. It is a little slow and the default user interface will always look fake compared to normal Windows components. (Yes I know that this can be solved by using libraries like SWT which let you use native gui components. I already knew Java's Swing so I used it.) Other than that I can't think of any real weaknesses. Forge is a relatively straightforward program and I always knew that I could coerce Java to do my biding given enough time.

Java seems to be one of the more popular languages, at least according to langpop.com, which uses a variety of sources in order to calculate the popularity of computer languages. Language popularity is important because people might submit code if they know the language. Forge has around 3 active coders and two of them learned Java just so they could help out, "Hi Rob and Chris." (I'll say hi to Dennis, the current lead developer, so he won't feel left out.)

Other Magic programs that I know of have used languages other than Java. Incantus uses Python which lets you easily create higher order functions and has other properties of a dynamic language. Wagic is designed to work on a PSP uses C++ and has to deal with limited memory issues. (Just thinking about memory issues scares me half to death.) MagicWars uses Java and is based on Forge's code. And Firemox uses Java also.

For a quick summary of the above programs:
Player versus player over the Internet: Incantus, MagicWars, Firemox
Player versus the computer: Wagic, which also runs on Windows, Linux, Mac

Make sure to come back on Wednesday, I'll be posting a new version of Forge.

p.s.
On a side note, I have also taken Sun's Java Programmer's test. The test really helped me understand Java because it went over some obscure details. I would recommend taking a certification test for whatever language that you use the most because it would challenge you to learn the "nooks and crannies" that you normally overlook.

p.p.s.
And the most green mana symbols on a card goes to....Khalni Hydra with an outstanding 8. How many years will this record last? Who knows?

p.p.p.s.
I can’t seem to get done, too many postcripts. “C makes it easy to shoot yourself in the foot. C++ makes it harder, but when you do, it blows away your whole leg” from Bjarne Stroustrup, creator of C++. I got that quote from the oustanding book “Expert C Programming” by Peter van der Linden. The book is mostly about C and answers obscure questions about C and dives in the mysterious world of pointers.

The book also answers the question of why this code snippet doesn’t compile. “Since the types char ** and const char ** are both pointers to unqualified types that are not the same type, they are not compatible types.

foo (const char **p) {}

main(int arg, char **argv)
{
foo(argv);
}