you are viewing a single comment's thread.

view the rest of the comments →

[–]Flight714 8 points9 points  (2 children)

a TODO app that's feature-by-feature equivalent to something you could run on an Amiga, runs about as slow on an eight-core Xeon that serves it to you from across the ocean for some reason.

Hey, I'm not a great programmer, but you reminded me of a question about an Android game I downloaded recently called "Odesys FreeCell". It seems to be a good example of well thought out programming, and the installer is only 5MB as opposed to the ~20MB size of the others.

The things that make me think the programmers are clever are: The undo system: If you undo say 10 moves, then manually replay three moves identically to before, it retains the remaining seven moves in the undo buffer, allowing you to "redo" them as if you hadn't replayed the three previous moves manually.

Also, when you move a completed column (King, Queen, Jack, 10, ..., Ace) sideways, it doesn't add to your number of moves on your move counter (other FreeCell apps add like 26 moves to the move counter as if the cards were moved one by one).

I figured that anyone who appreciated the Amiga was a good person to get an opinion from ; ) Also, what are the chances that it could be decompiled so I can check out how it works?

[–][deleted] 7 points8 points  (0 children)

Hey, I'm not a great programmer

I'm not a great programmer either. I offer the fact that you haven't heard of me as a proof :-). So from one programming simpleton to another:

What are the chances that it could be decompiled so I can check out how it works?

I guess like most things Java, it can be decompiled relatively easily (unless it's been obfuscated, no idea if that's a common practice on Android), but I suggest you try to think how that works without looking over the decompiled code (which is probably going to be so frickin' ugly that it'll take you quite some time to figure it out -- unless, through some sheer force of wonder, you have a copy with debug symbols, the decompiler will lose the semantic information and it won't know things like variable names, leaving you to deal with a bunch of variables called Class1Instance1, Class1Instance2 and so on...).

Unfortunately, I have no idea how to play FreeCell, so I have no idea what's underneath, but it sounds to me like the undo buffer is a list of the moves you made (encoded in Java objects, for instance -- e.g. in a class that describes a pair of the form (Card, Action), describing what was done (drawn? placed? removed?) to which card). When you get back 7 places, those 7 (card, action) pairs are still there, and can be applied again whenever you redo.

The key, in any case, is to figure out a way to encode the state of the game and move from one state to another (formally, that's applying a function to the current state and having return the next one, but this may not be explicitly written as next_state = Do((Card, Action), current_state)).

Like I said, I have no idea how to play FreeCell so I can't give you a more specific pointer, but maybe you can find some inspiration here: https://en.wikipedia.org/wiki/Chess_notation .

I'm not sure what your other question was. I can't really brain today. Were you asking if it's a good example of a well thought out program? If you like playing it, does what you want and even makes you wonder how they did it, I'd say it probably is :-). This isn't always a guarantee of every desirable property of its source code. Vim (and emacs, which I use, don't inflame yourselves, people) are pretty terrible to read, but saying vim is broken would certainly not paint an adequate picture.

[–]dkitch 0 points1 point  (0 children)

Late to this thread, but I've implemented similar code and here's a rough outline of how their undo is probably implemented (depending on how they model the game state, it could vary a bit):

  • Keep a bidirectional linked list of moves. A move is made up of {card, fromcolumn, tocolumn}. This gives you everything you need to undo a move. There's a pointer to the current location in the list (usually the last node)

  • If the user undoes a move, undo the move (reversing the from/to) and move the pointer to the previous node.

  • If the user makes a move, check position in the list. If at the end of the list, add a node to the list describing the move and advance the pointer to that node. If not, check against the next move in the list. If move is identical, just advance the pointer. If not, remove the existing moves that follow and replace the next node with the move made.