- OK, this is it. It's time for a MAJOR rewrite of the game engine interface.
The current design of b0rken inheritance hierarchy is starting to cause
nightmares with the network code.
- players and game engines should be separate entities. Game engines contain
players, but players (i.e. the current AI player) is NOT a "type of" game
engine. Should have a separate player class which can then contain stuff
like scores, nicknames, etc..
- players and interfaces are distinct things; the "human" player should
simply be derived from a base player class in such a way that it connects
to the interface. So XAtom-4 has an X11 player, textui has an ncurses
player, etc.. Similarly, the AI player is its own player. Network players
will just be another type of player. Interfaces should know how to work
with any player type (the specialized player type for that interface can
simply be an "active" class hooked off eventloop that triggers state
changes in the interface; no need for special handling in the interface
- game state change notification should also be expanded to cover events
like round over, change of turn, etc.. Interfaces shouldn't have to keep
on examining game state (although that should certainly be possible too).
- Add history and playback capability
- need network play! :-)
- all the infrastructure is in place, just have to actually implement the
network communications layer.
+ then attach textui to a fake game engine which is actually a network
client that connects to the server. We'll have to change make_move()
so that it will know to wait for a network response instead of asking
the user for a response. (Although now it's arguable whether this should
be in class interface instead of something else...)
X replace textui with a network interface, which basically acts like
a game server;
+ have textui able to choose between the real engine and a network engine.
+ textui will have two modes: standalone mode, where it gets input for
both users, and network mode, where it gets input for one player from
console, and the other from network.
- AI: profile a search, and see if we can't optimize it by caching hdelta's.
* actually, hdelta's are the least of your worries. The current big CPU hog
appears to be find_legal_moves(). (Unsurprising; it has to scan the entire
board to determine legal moves, and checks 6 neighbours per cell.)
- implement permanent AI subprocess first! We can't cache anything if we're
fork()ing each turn. We should probably just implement network play and
have the AI communicate over the network layer. No need for yet another
interface when one would do!
- AI: make pcreated, pdestroyed weights configurable.
- AI: add optional delay, so that we can (potentially) pit two AI's against
each other :-)
- more helpful failure codes from game::move(). Preferably we should
standardize messages in the game engine instead of relying on the interface.
+ need to mark up board with coors so that players can see where to move;
or alternatively, cycle ncurses cursor through all legal moves.
+ need to reset last_x,last_y and clear messages pane after restarting new
+ add color to pieces :-)
+ BUG: board window is one column smaller than it should be ('cos odd rows
are shifted right, and require one more column to fit!)
+ should clearly indicate which color is which player (display player headings
in the appropriate color!)
+ CRITICAL BUG: check_win() does NOT correctly detect wins if the last marble
placed is in the center of the row of 4 instead of either end.
X split off base class interface and subclass textui... then we can have a
network interface, e.g.
* Unnecessary. Just write a new UI. There is no compelling reason to use
the same base class anyway, since the only public method is run()!
X need to have independent player class (for scorekeeping and for keeping
track of colors, etc) -- although maybe it's good enough to keep this in
* scorekeeping is now in the game engine, as it should be.
X need to clean up board representation; ideally, EMPTY_CELL should = 0, and
BAD_CELL should = -1, and players' pieces should be stored as the player
+ implement new version of game, just to get a proof-of-concept of the new
2-player, 3-colors idea.
* Hmm, it's harder to balance than I thought. Because of the way the
colors are alternated, whoever lays down the N-1'th piece in a row will
almost certainly lose; so there's not much motivation except to play
defensive, in which case it's impossible to win.
* Sounds like in order for this to be plausible, we're gonna have to explore
the 8-color scheme.
+ need to implement a true multiplayer interface for game engine
+ game engine will be modal: DUAL (current), PEER (interface represents
only a single player), WATCH (only receiving updates, not playing).
+ fix X11 interface to support modal engines!
X should separate client from interface, maybe?
X another idea: have game engine require two players to "plug in"; but
we can connect the same interface to the engine twice to get the
+ generalize class interface to allow integration with X11 client.
+ Clean up class atom4local mess!!!
+ should inherit from triboard and put all color-manipulation stuff in there.
X Probably the best way is to templatize class triboard.
+ implement copy ctor for class triboard, so that it's easier to implement
state-space search algos for the AI.
+ fix -a so that we can specify which player AI should be.
+ Implement AI player! It's a tad boring to play against myself :-P
+ can have configurable AI, assigning different weights to the following:
+ single-depth scores:
+ number of colors a move changes
+ number of propagators a move creates
+ number of opponent propagators a move destroys
X number of opponent propagators vs. number of our propagators in
resultant state space
* Probably not necessary
+ recursive state-space searching scores:
+ even depths (opponent's turn):
+ losing move: if opponent has a winning move, assign negative score
+ (recursive) if all searched sub-moves result in states where
opponent has a winning move, assign negative score
+ instead of recursively considering all possible opponent moves,
only consider those we would pick if we were in that position
+ winning move: if a move causes a win, pick it for sure! :-)
+ implemented min-max algorithm. Strangely, it seems quite inferior in
terms of AI defense/offense (and takes a lot longer too!).
+ AI: implement a subprocess for the AI! that's what we have event loops for!
+ update README to explain the new 8-color game! :-)
+ [ncurses] should be updated to handle new 8-color system.
+ [ncurses] should be updated to support modal engines
+ make it easy to customize construction vars like PREFIX, DATADIR, etc.
* can just use Cons' %ARG feature.
+ BUG: fix varexception so that catch(exception) will work properly!!!!
+ it shouldn't just work for catch(exception&)
+ we should probably merge the two into the base class anyway, so that we
can do exception class hierarchies in a sane way.
+ BP: ambiguous prototypes exception(char*) and exception(char*, ...)
* one solution may be to use the first char of the message as indicator
(start with '@' for varexceptions). This should be minimally ugly,
at least better than introducing a new parameter!
+ BUG: atom4 cannot be suspended with SIGSTOP; upon resume, event loop dies
with Interrupted Syscall exception. (Should probably catch this condition,
since it is something to be expected. Also, should probably make sure we
don't die if 0 fd's are selected, which would happen when the process
resumes after a SIGCONT.)
+ BUG: fix game engine so that it will detect stalemate (board filled up with
no winners). This may be rare, but you don't want to be embarrassed when
somebody actually manages to achieve that!!
* Simplest way is just to maintain a counter initialized with w*h and
decremented every time a non-blank piece is placed.
+ Write a tarball-building script! It's quite a pain to do it by hand each
+ Update the Debian package with the eventloop fix.
X [ncurses] need to handle SIGWINCH.
* May not need to after all; ncurses-dev comes with its own SIGWINCH
+ [ncurses] fix non-updating board background on PuTTY.
+ AI: why is min-max algorithm performing so poorly??
* 'cos you did it wrong, dummy! You're supposed to evaluate the heuristic
function only at leaf nodes. Otherwise the min-max propagation becomes
meaningless, since it would effectively yield the path that leads to
the best move (in terms of the color changes heuristic), rather than the
path to the best game state.
* somehow, the heuristic algorithm seems to perform best at depth=2. Trying
depth=4 doesn't yield much improvement at all, and is just boringly slow.
+ implement REAL min-max algo!!!
+ IDEA: still base heuristic score on per-piece changes, but accumulate
them in a struct, only evaluate them at leaf nodes. Then propagate them
back using a real min-max selector.
+ this way, we can actually implement alpha-pruning...!
+ BBBBP: min-max algo still seems to perform horribly poorly. :-/
* Because you did it wrong again you dolt!!!! You forgot to invert hdelta
between turns, so enemy advances were counted as gains!!! You fool!!!!
+ argh, something is SERIOUSLY wrong with your implementation!! It's not
even detecting losing moves.
X Must be that max=-min parameter, I think...
* argh, something's wrong, it's not even detecting winning states...
+ Aha, found problem: in pick_best_move(), we treat equal scores equally;
but pruned subtrees return max, which may get equal score with another
non-pruned subtree. This is OK in score_opponent_move() because we use
> instead of >=. But pick_best_move() uses >=, so it misidentifies a
pruned branch as a good move.
* FIXED!! Let's see how well it performs now...
+ [ncurses] do a message("") after board change happens (AI moved), so that
the "it's not your turn" message doesn't continue sticking there after it
*is* your turn. Or better, print a message saying what the AI moved.
+ AI: min-max algo is *still* not doing very well at increased search depths.
At least -d2 seems to be at the same level as the original heuristic algo.
-d3 and -d4 seem to be a regression though :-( Must be a problem with the
heuristic value function...
+ Ack! Looks like there's a bug in the score propagation code. Negative
scores from AI's turn doesn't change sign when propagated to opponent's
* FIXED!! Now the AI is pretty formidable at -d3 !!
+ [ncurses] After AI moves, should restore cursor pos to current board pos,
else it looks misleading and player may make a mistake.
+ BUG: fixed incorrect negation of hdelta in AI. AI seems to be acting more
rationally now. :-P
* Wow, -d3 is now quite hard!
+ BUG: event loop postponed adds/deletes are inconsistent when the same fd is
added/deleted within a single dispatch cycle. Before appending a new entry
to the added/deleted list, we should check if it's already in the other list
and remove it from the other list if necessary.
+ eventloop: we REALLY need to implement timers now. Use gettimeofday() to get
the same precision select() uses.
+ Add timer to event loop