End Program in Python

A place to discuss the implementation and style of computer programs.

Moderators: phlip, Moderators General, Prelates

rhetorical
Posts: 103
Joined: Wed Apr 21, 2010 12:44 am UTC

End Program in Python

Postby rhetorical » Sun Nov 07, 2010 11:26 pm UTC

I am working on a text-based game for a school project, and I have run into a difficulty. At on point in my program, the user has to make a choice between two paths, one of which allows him to continue, while the other kills him. I am trying to get the program to end as soon as the player dies, but I can't find a way to do that. My first thought was a 'while' loop, in the same form as the following,

Code: Select all

dead = 0;

while dead == 0 :

     [Game goes here]

     if choice == 1:

          [Continue on]

     elif choice == 2:

          dead = 1;

     [Game continues here]


but that didn't work. I don't know of any other ways to end the program in the middle.


Thanks.

User avatar
flying sheep
Posts: 63
Joined: Sun Jan 31, 2010 12:35 am UTC

Re: End Program in Python

Postby flying sheep » Sun Nov 07, 2010 11:45 pm UTC

sys.exit()

keeperofdakeys
Posts: 658
Joined: Wed Oct 01, 2008 6:04 am UTC

Re: End Program in Python

Postby keeperofdakeys » Mon Nov 08, 2010 2:32 am UTC

Besides that semi-colon that should work. The only two scenarios I can think of is that 1. the choice variable is not being initialised (this has to happen in [Game goes here]), or 2. [Game continues here] does something unexpected (this may want to be moved to the [Continue on]?)

You might be interested in the break and continue statements.
Break will force the while loop to instantly exit, so all remaining statements in the loop are not executed.
Continue will stop the current iteration of the loop and restart the while loop from the beginning (it also re-checks the condition, skipping the while loop if it is false).

Aside: Break and continue should be used sparingly, like goto, as it can make code harder to read and can usually be avoided by using an approach similar to yours. There are other situations where they make code much easier to read though.

User avatar
Patashu
Answerful Bignitude
Posts: 378
Joined: Mon Mar 12, 2007 8:54 am UTC
Contact:

Re: End Program in Python

Postby Patashu » Mon Nov 08, 2010 2:32 am UTC

You could also throw an exception, but that's messy.

User avatar
phlip
Restorer of Worlds
Posts: 7572
Joined: Sat Sep 23, 2006 3:56 am UTC
Location: Australia
Contact:

Re: End Program in Python

Postby phlip » Mon Nov 08, 2010 2:48 am UTC

It sounds like you're expecting it to break out of the middle of the "while" block, when you set the "dead" variable to 1... that's not how it works. It only checks the condition on the while loop when it gets to the end of the block... then it checks the condition, and if it's false it'll drop out, but if it's true it'll go back up to the start.

For what you want, you have a few options. First is the simple:

Code: Select all

dead = 0
[Game goes here]
if choice == 2:
  dead = 1
elif choice == 1:
  [Continue on]
  [Game continues here]
This is the simplest if your "Game continues here" is relatively short... but if it's quite long, and especially if you are going to have several of these conditions, then you'll end up with massively nested ifs, which will just be ugly.

Another option is that if you are going to keep the "while" loop (because you want the actual loop, if you're not just using it as a way to stop running a block of code) is:

Code: Select all

dead = 0
while dead == 0:
  [Game goes here]
  if choice == 1:
    [Continue on]
  elif choice == 2:
    dead = 1
    break
  [Game continues here


Also, you can put the code in a function, so you can use return:

Code: Select all

def game():
  dead = 0
  [Game goes here]
  if choice == 1:
    [Continue on]
  elif choice == 2:
    dead = 1
    return
  [Game continues here]

game()


sys.exit or throw are also options, but not ideal... sys.exit will quit the program entirely (so you it would be hard to add, say, a "do you want to play again?" prompt at the end), whereas exceptions should only be used for actual errors, not stuff that happens normally during the game (like the player losing).

Of course, in all of those examples, if you don't use the "dead" variable for anything else, elsewhere in the code, you can get rid of it entirely.

Code: Select all

enum ಠ_ಠ {°□°╰=1, °Д°╰, ಠ益ಠ╰};
void ┻━┻︵​╰(ಠ_ಠ ⚠) {exit((int)⚠);}
[he/him/his]

0xBADFEED
Posts: 687
Joined: Mon May 05, 2008 2:14 am UTC

Re: End Program in Python

Postby 0xBADFEED » Mon Nov 08, 2010 1:46 pm UTC

phlip wrote:sys.exit or throw are also options, but not ideal... sys.exit will quit the program entirely (so you it would be hard to add, say, a "do you want to play again?" prompt at the end), whereas exceptions should only be used for actual errors, not stuff that happens normally during the game (like the player losing).

Actually in Python the two situations are equivalent, sys.exit() just throws a SystemExit exception which is catchable like any other exception. It usually propagates all the way to the top-level because it doesn't extend from the base Exception class. I don't think that using exceptions for this kind of behavior is too bad an idea, especially if it's less complicated than the alternative. For instance, I wouldn't have a problem with something like:

Code: Select all

try:
    game_loop()
except GameOver, e: #someone won
    [print who won, etc]
except SystemExit, e: #exit requested
    if confirm_exit():
        raise

It may not be the most idiomatic or elegant way of dealing with it but it's explicit and readable enough.

User avatar
Zamfir
I built a novelty castle, the irony was lost on some.
Posts: 7591
Joined: Wed Aug 27, 2008 2:43 pm UTC
Location: Nederland

Re: End Program in Python

Postby Zamfir » Mon Nov 08, 2010 2:30 pm UTC

0xBADFEED wrote:
phlip wrote:sys.exit or throw are also options, but not ideal... sys.exit will quit the program entirely (so you it would be hard to add, say, a "do you want to play again?" prompt at the end), whereas exceptions should only be used for actual errors, not stuff that happens normally during the game (like the player losing).

Actually in Python the two situations are equivalent, sys.exit() just throws a SystemExit exception which is catchable like any other exception. It usually propagates all the way to the top-level because it doesn't extend from the base Exception class. I don't think that using exceptions for this kind of behavior is too bad an idea, especially if it's less complicated than the alternative. For instance, I wouldn't have a problem with something like:

Code: Select all

try:
    game_loop()
except GameOver, e: #someone won
    [print who won, etc]
except SystemExit, e: #exit requested
    if confirm_exit():
        raise

It may not be the most idiomatic or elegant way of dealing with it but it's explicit and readable enough.


I wouldn't be too happy with this. Now you have to make explicit rules about what parts of the game are allowed to throw GameOver and SystemExit, and inevitably someone is going to abuse those rules. Much better if subroutines are always expected to give control back to their calling routine (actual errors aside).

0xBADFEED
Posts: 687
Joined: Mon May 05, 2008 2:14 am UTC

Re: End Program in Python

Postby 0xBADFEED » Mon Nov 08, 2010 2:40 pm UTC

Zamfir wrote:I wouldn't be too happy with this. Now you have to make explicit rules about what parts of the game are allowed to throw GameOver and SystemExit, and inevitably someone is going to abuse those rules. Much better if subroutines are always expected to give control back to their calling routine (actual errors aside).

I agree in general, but there are times when this can break down, and the exception method starts looking more attractive (although in this specific case it's nowhere near the level of complexity that warrants it).

If you have some top-level logic that needs to handle N different status events that are generally detected K levels deep in the program logic at M different code locations, the process of threading the events back to the top-level starts to seriously complicate your code, where the exception-based case keeps it relatively clean and manageable. Detect a relevant status event? Just raise it.

Obviously, an alternate control strategy would be something like continuations, which may prove better or worse depending on your language and the specific structure of the problem.

User avatar
WarDaft
Posts: 1583
Joined: Thu Jul 30, 2009 3:16 pm UTC

Re: End Program in Python

Postby WarDaft » Mon Nov 08, 2010 2:46 pm UTC

The easiest way is probably to turn the action of dieing into a function, unless there is no where else in the game the player can possibly die.

That is....

Code: Select all

[Game before choice goes here]
if choice == badChoice:
    killPlayer()
[Game continues here]


Better yet...

Code: Select all

gameFork(challenge,success,failure){
  result = challenge()
  if result:
    success()
  else:
    failure()
}
Unless there is only one point you will ever want the player to make a choice which can result in *any* sort of success or failure.
All Shadow priest spells that deal Fire damage now appear green.
Big freaky cereal boxes of death.

rhetorical
Posts: 103
Joined: Wed Apr 21, 2010 12:44 am UTC

Re: End Program in Python

Postby rhetorical » Mon Nov 08, 2010 4:10 pm UTC

Thanks for all the input. I'm probably going to use 'break', as I have a generic game-over statement outside the while loop.

Thanks again.

User avatar
Zamfir
I built a novelty castle, the irony was lost on some.
Posts: 7591
Joined: Wed Aug 27, 2008 2:43 pm UTC
Location: Nederland

Re: End Program in Python

Postby Zamfir » Mon Nov 08, 2010 4:24 pm UTC

rhetorical wrote:Thanks for all the input. I'm probably going to use 'break', as I have a generic game-over statement outside the while loop.

Thanks again.

Just to be clear: your original code should work fine.

User avatar
Jplus
Posts: 1721
Joined: Wed Apr 21, 2010 12:29 pm UTC
Location: Netherlands

Re: End Program in Python

Postby Jplus » Mon Nov 08, 2010 4:44 pm UTC

rhetorical wrote:Thanks for all the input. I'm probably going to use 'break', as I have a generic game-over statement outside the while loop.

Thanks again.

In that case you might be interested in a very nifty feat of Python:

Code: Select all

loop:  # i.e. a while loop or a for loop
    # do various things
    if some_condition:
        break
    # do more things
else:
    # the code in this block is only executed if some_condition was not met,
    # in other words, if the loop completed normally without breaking
# in either case, program continues here

You try the if statement every time you go through the loop, and as soon as you succeed you jump to the code after the else statement. However, if at the end of the loop you still didn't succeed, you apply the else statement. Pretty much like a very long stretch of "if, else if, else if, else if... else", but dynamically generated.

You can do something similar with goto statements in C and C++:

Code: Select all

loop {  // again, this might be for, while or do-while
    // do various things
    if (some_condition) goto banana;
    // do more things
}
// code that will be skipped if some_condition is met and
// the loop is exited with the goto statement
banana:
// in either case, program continues here


People who tell you you shouldn't use break, continue, goto, etc. really don't understand the point of structured programming. The only thing that was bad about goto statements in old languages like FORTRAN is that they were used for everything, including loops and functions, which makes it very hard to read large programs. Structured programming strongly improved upon this by introducing nested blocks (functions and loops), which are much more elegant, but that doesn't mean you're not allowed to use break/goto/continue/return-in-the-middle anymore. It would be ridiculous to completely do away with them, because that would require the programmer to invent all kinds of inefficient workarounds (such as storing an additional boolean just to know afterwards whether you actually would have wanted to jump).
(If anyone strongly disagrees and thinks I'm talking blasphemy, I invite them to branch of a new thread in the Religious Wars forum rather than going into discussion here.)

Oh by the way, Python also got the easily accessible quit() function which can be called from anywhere in your code.
"There are only two hard problems in computer science: cache coherence, naming things, and off-by-one errors." (Phil Karlton and Leon Bambrick)

coding and xkcd combined

(Julian/Julian's)

rhetorical
Posts: 103
Joined: Wed Apr 21, 2010 12:44 am UTC

Re: End Program in Python

Postby rhetorical » Mon Nov 08, 2010 5:56 pm UTC

Thanks, Jplus.

User avatar
Yakk
Poster with most posts but no title.
Posts: 11128
Joined: Sat Jan 27, 2007 7:27 pm UTC
Location: E pur si muove

Re: End Program in Python

Postby Yakk » Mon Nov 08, 2010 6:26 pm UTC

If I was writing a text-based game, I'd do it as a state machine.

Each state has a prompt and a menu (alternatively, it can be executed). It returns the state that you are transitioning to.

The main loop of the problem is then as simple as:

Code: Select all

 State = GetInitialState();
 while (State != ExitState)
   State = State.execute();

Now, with this system, your death state can be distinct from your exit state. Ie:

Code: Select all

DeathState::execute()
  print "You died, so sad."
  return ExitState

now, instead of transitioning directly to ExitState, the game transitions to DeathState when you die.

You can make things more advanced -- you can maintain a history of the states that the player was in:

Code: Select all

  StateStack.push(GetInitialState());
  while (!StateStack.empty() && StateStack.top() != ExitState)
    Retval = StateStack.top().execute()
    if (Retval == PopStack)
      StateStack.pop()
    else
      StateStack.push( Retval )

and it can get as fancy as you like (even giving the states access to the state stack).

The point of this is that instead of recursing through functions, you explicitly store state and then use the state to determine what happens next.

Going further, you can then move more of the game into data -- have descriptions of rooms be stored in files rather than directly in code -- and load those files and display them in uniform code. Code generates bugs, while data can be validated by code easier than code can be validated by code -- so by reducing the amount of code you have, your project is easier to debug.

Does this make sense?

(an example of a 3 room game, done in pseudo-code:

Code: Select all

room1::execute()
  print "There are exits to room 2 and 3 here.  Pick a room to go to."
  choice = getUserChoiceFrom( ["2", "3"] )
  if (choice == "2") return room2;
  if (choice == "3") return room3;
  # We will only get here if the user chose to quit the game
  return ExitGame

room2::execute()
  print "this room is a death trap.  Bye!"
  return ExitGame

room3::execute()
  print "there are exits to room2 and room 1 here.  Pick a room to go to."
  choice = getUserChoiceFrom( ["2", "1"] )
  if (choice == "2") return room2;
  if (choice == "1") return room1;
  # We will only get here if the user chose to quit the game
  return ExitGame

Note that the above is psuedo-code. You'd have to dress them 3 objects up in python-esque class trappings. You'd also have to write getUserChoiceFrom( list ), which prompts the user for a choice from the list (and possibly allows the user to Quit as well).

The above is extremely rough. In practice, I'd write a single class, and it would have a room description, possibly a list of items in the room (which would have descriptions attached), possibly some state (so you can, for example, open a door and it would be reflected in the description), commands you can do (and a table that describes the results of the commands, which can vary from going to another room to running a method on the object), etc.

Eventually, this kind of system is used in rather high end games -- the "state machine" loop I mentioned is the "game loop" of the game. Windowing programs create a message loop that looks sort of like it as well, where messages cause code to be executed.
One of the painful things about our time is that those who feel certainty are stupid, and those with any imagination and understanding are filled with doubt and indecision - BR

Last edited by JHVH on Fri Oct 23, 4004 BCE 6:17 pm, edited 6 times in total.

troyp
Posts: 557
Joined: Thu May 22, 2008 9:20 pm UTC
Location: Lismore, NSW

Re: End Program in Python

Postby troyp » Tue Nov 09, 2010 4:20 am UTC

If there's clean-up work to be done before exiting, you can always just write an "end_game()" function. THis would do whatever needs to be done and then call sys.exit().
It won't matter where you call it from, since it's never going to return anyway.

User avatar
Zamfir
I built a novelty castle, the irony was lost on some.
Posts: 7591
Joined: Wed Aug 27, 2008 2:43 pm UTC
Location: Nederland

Re: End Program in Python

Postby Zamfir » Tue Nov 09, 2010 6:30 am UTC

Listen to Yakk. His concept is simple to do, and would make your life a lot easier.

duckling
Posts: 4
Joined: Tue Nov 23, 2010 12:03 am UTC

Re: End Program in Python

Postby duckling » Tue Nov 23, 2010 12:10 am UTC

I just stumbled across this thread while searching for a solution to a similar problem. Exceptions would match my control-flow needs very well, but feel "wrong" on principle.

Yakk's solution seems like the most sensible option, but I am very puzzled how to implement something like that over a protocol like HTTP where the state machine must be re-loaded and the current state re-evaluated from scratch on each request, and the state machine must exit to return a response.

Any suggestions?

Thanks!

keeperofdakeys
Posts: 658
Joined: Wed Oct 01, 2008 6:04 am UTC

Re: End Program in Python

Postby keeperofdakeys » Tue Nov 23, 2010 12:04 pm UTC

duckling wrote:Yakk's solution seems like the most sensible option, but I am very puzzled how to implement something like that over a protocol like HTTP where the state machine must be re-loaded and the current state re-evaluated from scratch on each request, and the state machine must exit to return a response.

Any suggestions?

Thanks!

Wouldn't you store a 'session' (with current state) as a server variable using cookies (or directly using cookies). Then you use the cookie to identify the session, read the current state, perform the appropriate operation with the input, then set the new state and return it to the client? So something like a case statement.

The point is that you can't really use a program that stores the state during execution, you must have a way of saving state and probably want different sessions as well. This is still a finite state machine, but the program only modifies the state; one execution of the program is not the entire machine, just a part of it.

User avatar
Yakk
Poster with most posts but no title.
Posts: 11128
Joined: Sat Jan 27, 2007 7:27 pm UTC
Location: E pur si muove

Re: End Program in Python

Postby Yakk » Tue Nov 23, 2010 12:30 pm UTC

You don't even need a cookie. You could use a cookie -- or you could toss a GUID into the url (say, after a ?, or a /).

You can even do a state machine completely stateless -- store the state description in get or put statements, or in the cookie itself. But that both limits you, and makes "hacking" trivial (it basically turns your game into a choose your own adventure book -- change the page, change the state of the game).

(naturally you can encrypt and error-check the state above. You have what, 4k to play with in a cookie? However, the on-server session state with a cookie being nothing but a session variable system may be much easier, and allows for some features that the "store in cookie" version lacks.)
One of the painful things about our time is that those who feel certainty are stupid, and those with any imagination and understanding are filled with doubt and indecision - BR

Last edited by JHVH on Fri Oct 23, 4004 BCE 6:17 pm, edited 6 times in total.

duckling
Posts: 4
Joined: Tue Nov 23, 2010 12:03 am UTC

Re: End Program in Python

Postby duckling » Tue Nov 23, 2010 1:10 pm UTC

We're storing session IDs in cookies. The "rooms" and current state are stored entirely in a database because the application is served both over HTTP and over a protocol that's even more stateless, where we have access to only user IDs. Currently I have the whole thing running on about a hundred nested if-statements in a single main method. I've factored several large chunks out, but many of the rest can't easily be refactored into functions because they only sometimes return exit conditions, and it's starting to become unmaintainable.

This project isn't specifically a text-adventure game, but close enough. The trouble is that on each page load, the server needs to verify that the user is logged in, has an active valid account, that the account hasn't expired, whether they're trying to log in with a new account (which is allowed but then needs to be verified), that they've selected a game, whether they're asking to leave that game and play a new one, that the game they've selected is one they're allowed to play, that the game hasn't been completed, then which room-equivalent they're in, what type of "room" it is (there are different types that have different rules, so to speak), which of about a half-dozen states they're in within that "room", and what the next state and browser output should be based on the input. Overall, there are at least 30 possible states even for a game with only one room; 75% of states are exit-for-now (i.e. return a response and shut down) states, and each state has at least two different next-states depending on the input.

My concern with the state definition objects you suggested, Yakk, is that on every request, we're basically initializing the state machine from scratch and determining the user's place in the state machine all over again (see the steps above). The confusion for me is that there are two types of exit states -- one that exits the current request, shuts down the state machine, and returns a response, but doesn't exit the game, and one that actually exits the game.

Actually, I think I'll try to actually program the thing, and see where I'm getting stuck.

Thank you for your help!

User avatar
Yakk
Poster with most posts but no title.
Posts: 11128
Joined: Sat Jan 27, 2007 7:27 pm UTC
Location: E pur si muove

Re: End Program in Python

Postby Yakk » Tue Nov 23, 2010 2:42 pm UTC

Ah yes -- but much of what you describe can be dealt with via abstraction.

The layers that decide who the user is -- those should be abstracted away. The decision should be made, and then the rest of the code shouldn't have to worry about it.

Are you worried about performance? What technologies are you using (ie, how low level?)

If I was doing near-metal level tech, I'd be doing featherweight object instances.

If I wasn't worried about performance, I'd be tempted to code things up in a language that allows for program-state serialization. Then cheat with calls to something like suspend, saving the program state, and resuming it when the user calls back in.

If I was on an over-engineering kick, I'd write a light weight scripting engine that has limited state serialization optimized for the above situation.

If I was writing it in C++, I'd toss together a "game state" object with a "serialize" method (that did performance checks) and a "deserialize" method. It would load/save game state (for the entire game). I'd include performance metrics to keep myself from going insane. I'd allow sub-game states the right to register data for serialization. Inside the game state object, I'd use the state-machine model, with a feather-weight style "execute room" object (which can be switched out, based on an option in the current state). The entire thing would be designed so one instance of the C++ code could serve multiple users in sequence, to save on start-up shut-down costs. I do not, however, know if C++ is appropriate for this task.

A python approach would be different. I don't know enough php to know what approach I'd take using that.

How AJAX is your approach? I don't know AJAX well, but my understanding is that the server and the client keep a back-channel open between them -- which (might? dunno) imply that the server has a process that is sitting there waiting for user response.
One of the painful things about our time is that those who feel certainty are stupid, and those with any imagination and understanding are filled with doubt and indecision - BR

Last edited by JHVH on Fri Oct 23, 4004 BCE 6:17 pm, edited 6 times in total.

duckling
Posts: 4
Joined: Tue Nov 23, 2010 12:03 am UTC

Re: End Program in Python

Postby duckling » Tue Nov 23, 2010 4:27 pm UTC

Great points... I'll try to address them.

Yakk wrote:The layers that decide who the user is -- those should be abstracted away. The decision should be made, and then the rest of the code shouldn't have to worry about it.


They largely are -- although there are still portions of the main method dealing with the different states and responses returned for "if user not logged in", "logged in but hasn't chosen a game yet", etc. Most of the logic I can't abstract away at the moment is dealing with the actual steps through the "room", or with "meta" commands (e.g. "help" or "play a new game").

Are you worried about performance? What technologies are you using (ie, how low level?)


We're using Django (a RAD Python web framework). Our hosting environment appears to be constrained more by memory than anything so far; performance is an issue to the degree that we want to be able to handle several users at once and return their responses apparently instantly, but this isn't real-time or anything.

If I wasn't worried about performance, I'd be tempted to code things up in a language that allows for program-state serialization. Then cheat with calls to something like suspend, saving the program state, and resuming it when the user calls back in.


To be honest, I have no idea whether this is feasible in Python or how it would be done, if so. One of the reasons we're saving all state in the database (aside from the fact that Django makes a DB the most painless way to save and load data) is that it makes it very easy to gather statistical data, or for our staff to go in through an administrative interface and adjust game state in response to a support call.

How AJAX is your approach? I don't know AJAX well, but my understanding is that the server and the client keep a back-channel open between them -- which (might? dunno) imply that the server has a process that is sitting there waiting for user response.


We are not currently using AJAX because a large portion of our users are on older mobile browsers that we're not counting on to support it. I also would not be confident enough in the mobile networks' reception to keep a persistent connection open (and battery life then also becomes an issue).

User avatar
Yakk
Poster with most posts but no title.
Posts: 11128
Joined: Sat Jan 27, 2007 7:27 pm UTC
Location: E pur si muove

Re: End Program in Python

Postby Yakk » Tue Nov 23, 2010 5:01 pm UTC

How big of a game-pile are we talking about? If it gets large enough, making the games modular and detached from the main code is more important.

Python has pickle, which is a serialization library. The python "VM" is written in python, if I recall correctly -- but that might be perl I'm remembering. I could see you "blessing" variables as "must serialize", then enumerating those blessed variables for auto-serialization, and then "resurrecting" the state of the last execution from a database. I haven't seen anyone do full on suspend/resume in python, however. I don't know if that would be anywhere near fast enough.

...

Without AJAX, your typical connection would look like "the user has clicked on something, which we know about. We also know the users cookie, hence its database state. We need to evaluate the result of the users action, then quickly write out the users new state to the database (first! We don't want the user clicking before the database is updated! and if we start spewing HTML before the database update, that is quite possible), then in a fraction of a second respond with the HTML that represents the users new options?

I'm haven't written anything serious for the web -- but I'd be amused by a message-based system. The users action is translated into a message, which is then put through a message map that determines which control gets the message. The control is then resurrected from the DB and given the user action. It then decides what to do, then communicates to the game-engine (or whatever) with what should be done. The game-engine then changes state, then sends feedback to the front-end state (which figures out what should update) -- or, just changes state, and relies on the front-end pulling from it. (with a push-based system, the front-end components register with the game engine about what needs to be notified when whatever parts of the back-end change. The back-end works out what parts of the front-end need to be notified, then does a notification after game-state changes. This can reduce the amount of front-end code that needs to run each cycle in some cases -- one could imagine a front-end with pre-rendered html snippets for various parts. If one part is undisturbed, not having to rerender itself to html could save time -- just "repeat what I said before").

After all that happens, the front end is asked to render itself to html.

Interesting. That could be amusing to write.

Sadly, I don't know how Django works: and something like the above is at the scale of "write your own framework" rather than "use someone elses really cool and tested framework". The above also presumes a pretty dense UI: a game that exposes 3 choices is not worth anything like the above!

...

Ok, less pie-in-the-sky time!

In your framework, do you "hook python variables into the database"? It is pretty easy in python to turn passive variables into active-data that do database lookups depending on the current user, or that kind of thing. Does your python session extend between multiple users? Or is the python session built up and torn down for each user interaction?

I'd either have the "what the user sees" be data-driven (ie, the main method is "render the current page-state from data", which doesn't care if the user is logged in), or have fundamentally different code branches for the various extremely different states.

"Meta" commands are interesting. Is it layered?

One nice thing about state engines is that they can recurse, or you can augment them with a stack. Ie, your current game state can be independent of your current "interface" state.

Heck, you could have multiple current game states, with a distinct current interface state.

When you "enter" a game, your interface state is "in game X", at which point you examine your game state.

When you do something like "start a new game", the old game state need not be touched -- it could persist forever (in your database), or it could persist until your user commits to starting that new game (if you don't want to mess up your database with old game states that the user might not want).

Games themselves could have a two-layer state -- the "actual game state" and the "game interface state", where the two are mostly orthogonal.

So the fact that you are looking at a help menu has nothing to do with your "actual game state". The game state itself won't change (probably) due to what you do in the help menu -- but that's acceptable.

---

Ok, here is a non-crackbrained proposal. Something like this:

You have 4 layers of state.

Your login state. What user are you? Are you logged in? Do you need to be forced to pick a new password?
Your user state. Are you playing a game? Picking a new game? Chatting with bob?
Your game interface state. Are you starting a new game? Looking at help?
Your game state. Are you in room 7 with the sword of awesomeness?

The users request is a command. The command is interpreted by each of the above state machines from top to bottom.

Whichever catches it deals with it. They can "catch and deal", "don't deal with it, or "catch, modify and release" if they like. There are two kinds of "catch, modify and release" -- pass-through, and pass-back-to-top. The first is safer (code wise) because it doesn't risk infinite loops.

Once the command has been dealt with, you ask the website to render itself. Rendering goes through the above levels as well -- the login state can claim the rendering, then the user state can, then the game interface can, and finally the game state. Then you go back up, with each given a 2nd chance to render something (and is aware if the lower levels rendered something they consider "sufficient").

This rendering doesn't have to be to flat HTML, but it could be. It could be rendered to data structures that are later flattened. (I really don't know!)

You'll note that one neat thing about the above is that it makes it possible for a "pop-up" to "partially cover" a lower-level state. Ie, a chat window poping up while you are in a dungeon or something.

It also means that the game code doesn't know anything about the login engine. The functions are completely different.
One of the painful things about our time is that those who feel certainty are stupid, and those with any imagination and understanding are filled with doubt and indecision - BR

Last edited by JHVH on Fri Oct 23, 4004 BCE 6:17 pm, edited 6 times in total.

duckling
Posts: 4
Joined: Tue Nov 23, 2010 12:03 am UTC

Re: End Program in Python

Postby duckling » Tue Nov 23, 2010 5:49 pm UTC

Whoa, a lot to think about....

Yakk wrote:How big of a game-pile are we talking about? If it gets large enough, making the games modular and detached from the main code is more important.


What do you mean by a "game-pile"?

Sadly, I don't know how Django works: and something like the above is at the scale of "write your own framework" rather than "use someone elses really cool and tested framework".


Django basically locks you into a request-response cycle. The application itself is persistent (as long as the web server doesn't crash or get restarted) but each HTTP request is separated from the others and essentially MUST return an HTTP response. Anything that persists across requests must be stored in the session, or elsewhere in persistent storage and keyed to session.

The above also presumes a pretty dense UI: a game that exposes 3 choices is not worth anything like the above!


Yes. Our game is, as I said, not totally unlike a text adventure game: think of a text field and a few buttons.

In your framework, do you "hook python variables into the database"? It is pretty easy in python to turn passive variables into active-data that do database lookups depending on the current user, or that kind of thing.


Erm, I'm not entirely certain what you're asking. Django has an ORM that essentially abstracts database lookups into simple method calls on DB manager objects, returning objects or lists of objects representing the data retrieved; ditto for create/update/delete.

Does your python session extend between multiple users? Or is the python session built up and torn down for each user interaction?


Both, sort of. The application itself serves multiple users and the Python session persists across requests, but each request is built up and torn down separately, and the framework doesn't really offer any opportunity to do work outside a request/response cycle without running an independent background process.

I'd either have the "what the user sees" be data-driven (ie, the main method is "render the current page-state from data", which doesn't care if the user is logged in), or have fundamentally different code branches for the various extremely different states.


I'm not entirely certain how this applies. Since the interface is so simple, the page rendering is trivial (and the rendering given the current state is already abstracted out by Django's templating layer). The challenge is *returning* the HTML from whatever depth of the code path we're in.

"Meta" commands are interesting. Is it layered?


Layered how?

When you do something like "start a new game", the old game state need not be touched -- it could persist forever (in your database), or it could persist until your user commits to starting that new game (if you don't want to mess up your database with old game states that the user might not want).


Yes, we're currently persisting old game states in the database.

Games themselves could have a two-layer state -- the "actual game state" and the "game interface state", where the two are mostly orthogonal.


Not sure that really applies, given the simplicity of our interface.

Your login state. What user are you? Are you logged in? Do you need to be forced to pick a new password?
Your user state. Are you playing a game? Picking a new game? Chatting with bob?
Your game interface state. Are you starting a new game? Looking at help?
Your game state. Are you in room 7 with the sword of awesomeness?

The users request is a command. The command is interpreted by each of the above state machines from top to bottom.

Whichever catches it deals with it. They can "catch and deal", "don't deal with it, or "catch, modify and release" if they like. There are two kinds of "catch, modify and release" -- pass-through, and pass-back-to-top. The first is safer (code wise) because it doesn't risk infinite loops.


This is in essence what we're doing now (with pass-back-to-top in some conditions and pass-through in others), but in a single state machine, and without a separate interface state.

Once the command has been dealt with, you ask the website to render itself. Rendering goes through the above levels as well -- the login state can claim the rendering, then the user state can, then the game interface can, and finally the game state. Then you go back up, with each given a 2nd chance to render something (and is aware if the lower levels rendered something they consider "sufficient").


Here is where the approaches diverge. Currently when we "catch" we're simply passing HTML back to top, where we exit the machine entirely and return the HTML (interface rendering) to the user. I'm running into trouble abstracting out some pieces but still being able to pass back to top without throwing exceptions.

I'll be honest, I've read your previous post a few times through, and have had trouble figuring out how to apply much of what you've suggested -- and I can't tell whether it's due to lack of caffeine, because I'm just dense, or because it assumes a much more complex UI than we're presenting our users.

Either way, I very much appreciate your help and suggestions. Thank you.


Return to “Coding”

Who is online

Users browsing this forum: No registered users and 7 guests