Python (civ4 scripting language) tutorial thread

Nevermind I figured it out.

Here is a simple script that defines a deck of 52 cards and also includes a function that picks a random card. Each card is in a list like so:
Code:
[suit, cardnumber, 0]

Just rename .txt to .py It is meant to be imported. :)

Now on to Blackjack!
 

Attachments

@vbraun

Uh ... man you have to become lazy! ;)

If you want to define 52 cards, why don't you define them as a list of objects?
Example:

Code:
from random import *

class Card:
  # I'm not sure if the following lines are necessary
  self.type
  self.value
  self.reserved

  # These are definetly necessary
  __init__(self, type, value, reserved)
    self.type = type
    self.value = value
    self.reserved = reserved

# 52 cards are being created according to your sample here 
while i < 4
  i++
  while j < 13
    j++
    cardlist.append(Card(i, j, 0))

#Pick a random card
def pickcard(cardlist):
  return cardlist[randint(1,52)]

I did not test the code yet. But it should be something like that.
Almost all of your code is done in 7 lines (not counting the class definition, which offers of course even more options, like what card defeats an other and so on).
 
Poisos said:
Think of classes as your BLUEPRINTS for later manufactured objects! In your class definition you describe how you would build i. e. a car ... but since then there is no real car, right(only the pice of paper with your blueprint on it)? So you have to build a car according to this BP. This is done by making an instance of it.
In Python: myCar = blueprint_of_a_car()
Now the little "data elves" in your computer actually build a car named "myCar". Now you would be able to drive that car or accellerate it and so an (ever drove a blueprint :crazyeye: !?).

This brings us to inheritance and polymorphism.
If you would like to build a new car with special tires, seats or a different motor you wouldn't design a whole new car, now would you? Instead you would just change your motor or your tires and leave the rest as it is.
This is done by creating a new class (or blueprint) which inherits all the attributes and methods from your original car class (copy all information of your original blueprint to another) and then overrides the information i. e. of the type of motor what should be in the car (erase the data of your motor on your copied blueprint and specify another one).
Excellent! Will incorporate it into the redesign. You put it in real-world terms, and most people understand cars.

I am working right now on an civ related interface mod. Remember that you had to explicitly change single leaderheads in your civ3 foreign advisor screen if too many civs were in the game!? I'm working on a demo solution for that problem in Python where the leaderheads will organize themselves on a circle and scale down when necessary.
I want to try that using Tkinter objects, canvas, simple shapes (not even real images to scale ... keeping it as simple as possible). After all they said the INTERFACE would be modable.
So I WILL come back (for support :D ) and I am also planing on posting the solution here on cfc.
As a word of advice, I don't believe that tkinter is a really good interface to work with - it is a little limited. Try something like GTK (which requires extra files to be installed) or WxPython (which is cross platform, and uses the native-style buttons, etc. of the operating system it is running on.)
 
Gingerbread Man said:
Try something like GTK (which requires extra files to be installed) or WxPython (which is cross platform, and uses the native-style buttons, etc. of the operating system it is running on.)

Thanks for the hint!
 
Poisos said:
@vbraun

Uh ... man you have to become lazy! ;)
In programming, laziness is both a vice and a virtue!

[profound-ness]Try to do as much as possible, as clearly as possible, but writing as little as possible... such is the art of the programmer...[/profound-ness]

To use a random number generator between 0 and 51:
Code:
import random
random_number = random.randint(0,51,1)
don't use whrandom - as the warning says (at least in Python 2.4), whrandom is depreciated. That is to say, it is old, probably unmaintained and may be removed some day.

The list of objects idea is good. Here's what I'd do:
Code:
from random import *
# create the definition of a card
class Card:
    def __init__(self,suit,number,reserved):
        self.suit = suit
        self.number = number
        self.reserved = reserved

# build your deck
deck = []
suit = 0
num = 0
for i in range(1,52,1):
    if num > 12:
        suit = suit + 1
        num = 0
    deck.append(Card(suit,num,0))
    num = num + 1

# pick a random card
suitname = ['hearts','spades','diamonds','clubs']
cardname = ['Ace','two','three','four','five','six','seven','eight','nine','ten','jack','queen','king']
r = randint(0,51)
print "Randomly picked, was the "+cardname[deck[r].number]+' of '+suitname[deck[r].suit]
In fact, this works rather nicely. I could set it up to simulate a real deck, where the order of cards is predetermined, and the most recently used card is found at the bottom. try using random.shuffle to shuffle the deck. that would stop, say, 21 cards of suit diamonds occuring in the space of 30 picks (sure, its truly random that way, but is physically impossible, unless you're playing against people of... questionable tactics)
 
Poisos said:
@vbraun

Uh ... man you have to become lazy! ;)

If you want to define 52 cards, why don't you define them as a list of objects?
Example:
My first program, give me some slack. :p I was looking at a way with classes but ended up giving up and decided to take the easy way out.

Gingerbread Man said:
don't use whrandom - as the warning says (at least in Python 2.4), whrandom is depreciated. That is to say, it is old, probably unmaintained and may be removed some day.
I was going to mainly edit the whrandom file to get rid of that message :lol: switching to use random.

The reason I used whrandom is the documentation said vice versa! I assume the documentation was unupdated.

Time to go fix my code. :)

Edit: I copied and pasted this exactly:
Code:
import random
random_number = random.randint(0,51,1)
And now I get an error saying
Code:
TypeError: randint() takes exactly 3 arguments (4 given)

Thats really odd.

Edit2: By taking out the last argument it seems to work.
 
Gingerbread Man said:
The list of objects idea is good. Here's what I'd do:
Code:
from random import *
# create the definition of a card
class Card:
    def __init__(self,suit,number,reserved):
        self.suit = suit
        self.number = number
        self.reserved = reserved

# build your deck
deck = []
suit = 0
num = 0
for i in range(1,52,1):
    if num > 12:
        suit = suit + 1
        num = 0
    deck.append(Card(suit,num,0))
    num = num + 1

# pick a random card
suitname = ['hearts','spades','diamonds','clubs']
cardname = ['Ace','two','three','four','five','six','seven','eight','nine','ten','jack','queen','king']
r = randint(0,51)
print "Randomly picked, was the "+cardname[deck[r].number]+' of '+suitname[deck[r].suit]
In fact, this works rather nicely. I could set it up to simulate a real deck, where the order of cards is predetermined, and the most recently used card is found at the bottom. try using random.shuffle to shuffle the deck. that would stop, say, 21 cards of suit diamonds occuring in the space of 30 picks (sure, its truly random that way, but is physically impossible, unless you'r playing against people of... questionable tactics)
It fills deck with this: (doing a print deck)
Code:
[<__main__.Card instance at 0x2a955da050>, <__main__.Card instance at 0x2a955ec098>, <__main__.Card instance at 0x2a955ec0e0>, <__main__.Card instance at 0x2a955ec128>, <__main__.Card instance at 0x2a955ec170>, <__main__.Card instance at 0x2a955ec1b8>, <__main__.Card instance at 0x2a955ec200>, <__main__.Card instance at 0x2a955ec248>, <__main__.Card instance at 0x2a955ec290>, <__main__.Card instance at 0x2a955ec2d8>, <__main__.Card instance at 0x2a955ec320>, <__main__.Card instance at 0x2a955ec368>, <__main__.Card instance at 0x2a955ec3b0>, <__main__.Card instance at 0x2a955ec3f8>, <__main__.Card instance at 0x2a955ec440>, <__main__.Card instance at 0x2a955ec488>, <__main__.Card instance at 0x2a955ec4d0>, <__main__.Card instance at 0x2a955ec518>, <__main__.Card instance at 0x2a955ec560>, <__main__.Card instance at 0x2a955ec5a8>, <__main__.Card instance at 0x2a955ec5f0>, <__main__.Card instance at 0x2a955ec638>, <__main__.Card instance at 0x2a955ec680>, <__main__.Card instance at 0x2a955ec6c8>, <__main__.Card instance at 0x2a955ec710>, <__main__.Card instance at 0x2a955ec758>, <__main__.Card instance at 0x2a955ec7a0>, <__main__.Card instance at 0x2a955ec7e8>, <__main__.Card instance at 0x2a955ec830>, <__main__.Card instance at 0x2a955ec878>, <__main__.Card instance at 0x2a955ec8c0>, <__main__.Card instance at 0x2a955ec908>, <__main__.Card instance at 0x2a955ec950>, <__main__.Card instance at 0x2a955ec998>, <__main__.Card instance at 0x2a955ec9e0>, <__main__.Card instance at 0x2a955eca28>, <__main__.Card instance at 0x2a955eca70>, <__main__.Card instance at 0x2a955ecab8>, <__main__.Card instance at 0x2a955ecb00>, <__main__.Card instance at 0x2a955ecb48>, <__main__.Card instance at 0x2a955ecb90>, <__main__.Card instance at 0x2a955ecbd8>, <__main__.Card instance at 0x2a955ecc20>, <__main__.Card instance at 0x2a955ecc68>, <__main__.Card instance at 0x2a955eccb0>, <__main__.Card instance at 0x2a955eccf8>, <__main__.Card instance at 0x2a955ecd40>, <__main__.Card instance at 0x2a955ecd88>, <__main__.Card instance at 0x2a955ecdd0>, <__main__.Card instance at 0x2a955ece18>, <__main__.Card instance at 0x2a955ece60>]
 
vbraun said:
My first program, give me some slack.
Didn't mean to push you. For that reason I added a smiley :) .

vbraun said:
It fills deck with this: (doing a print deck)
Code:

[<__main__.Card instance at 0x2a955da050>, <__main__.Card instance at 0x2a955ec098>, <__main__.Card instance at 0x2a955ec0e0>, <

That is correct? Where is your problem?
It only tells you that an actual Object of type "Card" is at memory position "0xa955da050" (hexadecimal) and so on.
Can you not print your card values? I tested GBM's Code and it works with me!?

vbraun said:
And now I get an error saying
Code:

TypeError: randint() takes exactly 3 arguments (4 given)



Thats really odd.

Edit2: By taking out the last argument it seems to work.

See documentation for randint below:
http://www.python.org/dev/doc/devel/lib/module-random.html
 
Poisos said:
That is correct? Where is your problem?
It only tells you that an actual Object of type "Card" is at memory position "0xa955da050" (hexadecimal) and so on.
Can you not print your card values? I tested GBM's Code and it works with me!?

I couldn't get the card values to show. I fixed it by changing
Code:
deck.append(Card(suit,num,0))
to
Code:
deck.append([suit,num,0])
thus making the class unnecssary, and it works how I want it.

I also have each time a card is selected make it disapear from the deck so it can't be called again, untill I shuffle the deck with this:
Code:
for i in range(1,len(deck)+1,1):
	deck.pop(0)
suit = 1
num = 1
for i in range(1,53,1):
    if num > 13:
        suit = suit + 1
        num = 1
    deck.append([suit,num,0])
    num = num + 1

Right now my game of Blackjack selects 4 non-same cards (2 for the player and 2 for the dealer) and will check for a Blackjack/Bust/Under 21. Now I need to work on being able to hit/stay. :)

Edit: Got a basic hit system down
Here is some sample game ATM:
You have 7d Qd
Dealer has 2h Xx
What would you like to do?
h
You now have:
7d Qd 9h
 
vbraun said:
Code:
import random
random_number = random.randint(0,51,1)
And now I get an error saying
Code:
TypeError: randint() takes exactly 3 arguments (4 given)

Thats really odd.

Edit2: By taking out the last argument it seems to work.
Sorry, that was my mistake. I thought you could give it a parameter telling the steps between integers... :blush:

By the way, your blackjack game is a really good way of making simple AI. I'd encourage other people to make a text-based card game, and make an AI to go with it.

Keep the card game simple, like blackjack, so that you don't have to worry too much about the finer details of rules.
 
Hello again, I am now making my own program. Can someone tell me how to make a list of options(menu) for one of the things i have made. the one i want is self.girlfriend. I would like to make list of possible answears for this and if you choose one then the answear comes up in the finally part. I have attached two files. The main program and a module. You have to have both in the same folder, and run only the module
 

Attachments

I'd like you guys to give comments on my blackjack game so far. Right now it won't reconize Aces properly and the Dealer can't hit yet. Type h for hit and s for stay. Also if it says "Blackjack!!" it still asks you wether you want to hit or stay.

There is some comments so you can have some kind of idea whats going on.
 

Attachments

Seems like my post would become too big if I'd add my polymorphism description. So I post it here:
(See first part)

So where is polymorphism used?
I' ll try to make it simple at first. In my opinion the simplest thing you can do which can be described as polymorphism related is overriding functions and defining functions with the same name but a variable number of parameters.

For example you have a function which assigns RGB (RedGreenBlue) color values to object attributes. You can define two functions as follows:
Code:
def assignRGB(r, g, b):

or

valueList = [r, g, b]
def assignRGB(valueList):
This might seem not so overwhelmingly useful at first but that 's just because a program context is missing. In fact constructs like these can become very convenient during programming.
This technique is also called "overloading functions".

Overriding a function works differently. Imagine you created a class "Car" with a function crankCar(). In that function you would then call a function turnKey(), because that would be the first step for cranking your car.
Now you create a new class "ModernCar" which inherits "Car". You would already be able to use:
Code:
myCar = ModernCar()
myCar.crankCar()
But crankCar() would still turn a key. :nono: We don't like that for our new car. So we override that function through redefining it and calling pressStartButton() in this new version.
Code:
class Car:
    def _turnKey(self):
        print "Key turned"
        
    def crankCar(self):
        self._turnKey()

class ModernCar(Car):
    def _pressStartButton(self):
        print "Startbutton pressed"

    def crankCar(self):
        self._pressStartButton()
So we only have to know that we want to crank our car. How that actually works is defined in the crankCar() function of each class type :) (Aaahh .. "ignorance is a bliss" :D ).

You might wonder why I used "_" as first character in my function names. That describes a low private status of that funtion. "__" describes a high private status. What that means is that low private functions can not be used from outside the class unless you now their name and call them explicitly. (See Python documentation) As the Python documentation states, they're not imported by:
Code:
from module import *
In my example I just want to protect my "_"functions from easy external access so that an object user is only able to crank the car but not to turn the key or press the start button.

High private functions can not be called from outside the class at all. (By the way ... nothing that we realy HAVE to use right now! It's just for education ;) .)

However, I would say polymorphism is really about "morphing" types of objects into base types of their own class hierarchy or vice versa (which can get a litle bit dangerous in terms of program stability). But until now I'm not sure how this can be accomplished in Python :( .
Perhaps GBM can help us out!?

PS: @GBM ... I wonder if it is a good idea to link both posts on inheritance and polymorphism in your starting post. After all they are both almost a complete lesson :) . I will gladly edit them where necessary.
 
great post, Poisos :goodjob:
I find your explanation very clear.

I do have a question anyway about the private status.
high private : understood. Very useful in my view to prevent users to deal inadvertently with the inner mecanisms of your class.

But I'm not sure about low private status....
You have to know the name and call it explicitely... but what is the difference with the default status of classes elements ?
 
Hi. Only joined the forum a few days ago and have already posted almost 100 posts. I'm interested in this. I am a first year Uni student studing for a batchelor of information technology. I know:
DrScheme (training language they use at Uni), some JavaScript, HTML, ActionScript (yes I know these are not REAL programing languages). I am very good at the logic of coding and creating some really high quality flash games (at least at the code level) is one of my fovorite past times. And My Dad programs for a living.

I will try to start tommorow but I might not get a chance to really go through these till after my exams are done (a few weeks). Once I get into them though I should be up to scratch pretty quick.
 
JG99_Korab said:
Hello again, I am now making my own program. Can someone tell me how to make a list of options(menu) for one of the things i have made. the one i want is self.girlfriend. I would like to make list of possible answears for this and if you choose one then the answear comes up in the finally part. I have attached two files. The main program and a module. You have to have both in the same folder, and run only the module

In the lesson on functions, there is a menu function that is created. I think there are some other versions of it later in the tutorial. Either way, dig it up, and adapt it to fit your solution.

Posious - Excellent work! I'll be away for the (in Australia) long weekend, but will be able to help you later.

I could make space for contributed tutorials/HOWTOs on my site, but just remember that anything up there has to be clear, and leads off from what is already there (that is, assumes that the only knowledge the reader has is what they got from the site).

Old Lion - Again, I'll be able to help you in 3 or so days, after I get back from the break.

Meleager - thanks for dropping in :) . If you find any part difficult, let me know, because if the lessons are too difficult, then they aren't good enough to be for beginners.
 
Gingerbread Man said:
In the lesson on functions, there is a menu function that is created. I think there are some other versions of it later in the tutorial. Either way, dig it up, and adapt it to fit your solution.
I tried. I have the menu function but I can't figure out how to do it. Not really a menu. But just a yes or no option. and if answer is yes print "......." and if answear is no print.... Can you at least look when you have the time?
 
You link on the first page for the 2nd lesson goes to the wrong place.

And I've done lesson 1 :)
 
Hello all,
Good work on the tutorial Ginderbread Man.
Its nice to see someone willing to spend their valueable to help other potential cIV modders.

I have been working through the tutorial and got up to GM's mini adventure game. I was going through it to figure out how it worked and noticed a couple of interesting things.

Code from GM's Adenture game
Code:
location = objects
loop = 1
lastinput = []
while loop == 1:
    noprint = 0
    location = objects
    input = command(">")
    if input [-1] not in actions:
        print "Sorry, I don't understand the command \'" + input[-1] + "\'."
        continue
    if input[0] == "exit":
        print objects['exit']
        loop = 0
        noprint = 1
        break
    newcommand = lastinput
    for word in input: 
        newcommand.append(word)
    if len(input) <= 1:
        newcommand = input
    try:
        for entry in newcommand:
            location = location[entry]
    except:
        [I]location = objects #not in original program[/I]  
        [B]for entry in input:
                try:
                location = location[entry]
            except:[/B]
                print "Sorry, I don't recognise the object \'" + entry + "\'."
                noprint = 1
              [B]  break[/B]
    if noprint == 0:
        print location
    lastinput = input[:-1]

In this program code(exluding code in italics) the code in bold is rather useless and can be removed without affecting how the program runs in the least way.

However, if you insert the code in italics, the code in bold serves a purpose(does what it was likely originaly intended to).

before the code in italics was inserted the program would run like this:

> touch roof rust
The rust pokes through and water trickles from the hole you made.
Have a nice drink.

> touch roof rust
Sorry, I don't recognise the object 'roof'.

After code in italics was inserted:

> touch roof rust
The rust pokes through and water trickles from the hole you made.
Have a nice drink.

> touch roof rust
The rust pokes through and water trickles from the hole you made.
Have a nice drink.

If anyone want a better explanation :confused: on what I am talking about just say so and I will try explain what is going on.(I will never make a good teacher :( )
 
Back
Top Bottom