Monday, April 26, 2010

Mini RPG: Just Started

I have started on my mini-RPG! As of now I have a field and character class. The field has three obstacles in it now, and the entire field is represented by the currentMap list shown at the beginning of the source code. A 1 is a wall, 0 is empty space, 2 is an obstacle (not walkable), and 3 is a newline character.


At the moment the obstacles are represented by one of five different characters, and each obstacle is assigned one of these characters during the instantiation (creation) of the game field's instance. This way, random characters are generated for the obstacles and stay that way the entire game.

For now the only things that this does are create a field and print it when you hit enter, and move the character around. In order to detect collision I created an isValidMove function. This function checks to see if the next move the player can take will be anything but a 0 or not, and returns True or False.


import random

currentMap = [
    [1, 1, 1, 1, 1, 3],
    [1, 0, 0, 0, 1, 3],
    [1, 2, 0, 0, 1, 3],
    [1, 0, 0, 0, 1, 3],
    [1, 0, 0, 2, 1, 3],
    [1, 0, 0, 0, 1, 3],
    [1, 0, 2, 0, 1, 3],
    [1, 0, 0, 0, 1, 3],
    [1, 1, 1, 1, 1, 3]
    ]


class gameField:
    def __init__(self, mapData=[0]):
        self.mapData = mapData
        self.string = ''
        self.blocks = []
        for i in range(len(self.mapData)):
            for j in range(len(self.mapData[i])):
                if self.mapData[i][j] == 2:
                    r = random.randrange(1, 5)
                    if r == 1:
                        self.blocks.append(' v ')
                    if r == 2:
                        self.blocks.append(' x ')
                    if r == 3:
                        self.blocks.append(' ^ ')
                    if r == 4:
                        self.blocks.append(' * ')
                    if r == 5:
                        self.blocks.append(' ~ ')

class character:
    def __init__(self, x=0, y=0, field=None):
        self.crds = [x, y]
        self.x = self.crds[0]
        self.y = self.crds[1]
        self.field = field

    def __str__(self):
        s = ''
        r = 0
        for i in range(len(self.field.mapData)):
            for j in range(len(self.field.mapData[i])):
                if self.field.mapData[i][j] == 4:
                    self.field.mapData[i][j] = 0
        self.field.mapData[self.y][self.x] = 4
        for i in range(len(self.field.mapData)):
            for j in range(len(self.field.mapData[i])):
                if self.field.mapData[i][j] == 0:
                    s += '   '
                elif self.field.mapData[i][j] == 1:
                    s += ' / '
                elif self.field.mapData[i][j] == 2:
                    r += 1
                    if r == 1:
                        s += self.field.blocks[0]
                    if r == 2:
                        s += self.field.blocks[1]
                    if r == 3:
                        s += self.field.blocks[2]
                elif self.field.mapData[i][j] == 3:
                    s += '\n'
                elif self.field.mapData[i][j] == 4:
                    s += ' O '
        self.field.string = s
        return self.field.string

    def isValidMove(self, move):
        if move == 'a':
            if self.field.mapData[self.y][self.x - 1] != 0:
                return False
        if move == 'a':
            if self.field.mapData[self.y][self.x - 1] == 0:
                return True
        if move == 'w':
            if self.field.mapData[self.y - 1][self.x] != 0:
                return False
        if move == 'w':
            if self.field.mapData[self.y - 1][self.x] == 0:
                return True
        if move == 's':
            if self.field.mapData[self.y + 1][self.x] != 0:
                return False
        if move == 's':
            if self.field.mapData[self.y + 1][self.x] == 0:
                return True
        if move == 'd':
            if self.field.mapData[self.y][self.x + 1] != 0:
                return False
        if move == 'd':
            if self.field.mapData[self.y][self.x + 1] == 0:
                return True

currentGameField = gameField(currentMap)
currentCharacter = character(3, 1, currentGameField)

while True:
    print(currentCharacter)
    char = raw_input()
    if char == 'a':
        if currentCharacter.isValidMove(char):
            currentCharacter.x -= 1
    if char == 'd':
        if currentCharacter.isValidMove(char):
            currentCharacter.x += 1
    if char == 'w':
        if currentCharacter.isValidMove(char):
            currentCharacter.y -= 1
    if char == 's':
        if currentCharacter.isValidMove(char):
            currentCharacter.y += 1


After that is complete, I'll add in an option to enter your inventory and have a chance of a random battle sequence after each step the player takes.

Hopefully in the future I will have support for having multiple rooms, doors to and from rooms, and a .txt loader that can load maps from a .txt file. We'll see how things go.

Here is an example of some output text:

 /  /  /  /  /
 /           /
 /  v        /
 /  O        /
 /        ^  /
 /           /
 /     v     /
 /           /
 /  /  /  /  /

d
 /  /  /  /  /
 /           /
 /  v        /
 /     O     /
 /        ^  /
 /           /
 /     v     /
 /           /
 /  /  /  /  /


The character is the O, and the / are walls, the rest are just impassable obstacles. I hit the d key, and moved the character a space right. 

Monday, April 19, 2010

Card Simulation: Complete

I have finished my Mau Mau card game!!


There are now two "unique" cards. Playing a seven makes the next player draw a card, and playing an Ace makes the next player lose a turn. The face up stack now sets itself as the deck and shuffles when the deck empties. If a player plays all their cards in their hand they win, and the program exits using sys.exit().

I may in the future add in support for multiple Ai players, but for now I shall not. I want to start on a new and more complicated project, and I don't feel that working on this much more will help me to learn much more.

Currently 333 lines of code.

Here is a link to the .exe file in case you want to play it:

http://www.mediafire.com/?jjymynjngdz

Here is a link to the .py source file:

http://www.mediafire.com/?jnzum2zdrdv

As for my next project, I want to make a very small fighting game. The game will be text based, and will feature a small map, a battle sequence, and random battle events while walking on the map. I also want to have a interactive map (e.g. open doors), as well as a very limited inventory for dealing out different attacks. All in all, I want to have about 3 enemies. Basically this project is a mini-RPG, without upgradeable stats or any storyline. The point of the project is just to solidify my general coding capabilities, along with furthering my use of OO.

Saturday, April 17, 2010

Card Simulation: Continued


Here is a code update for the day. I have to spend the rest of my day doing homework, so I don't know what progress will be made throughout the weekend. I may work on this more tomorrow.

Here is a link to the current build's source code.

As you can see, I have an Ai working to play against me. I currently don't have anything to have a player win the game, so there should be an exception thrown during one of the Ai's methods or during the makeMove method when either player has no cards in their hand.

The Ai works by creating a list of cards available to play, then randomly choosing one to play. If none of the cards in the Ai's are playable then it will draw a card from the deck. This reminds me, if the deck empties then there should be a thrown exception as well, as I haven't coded switching the stack with the deck when the deck is empty.

Since I created an Ai class, I should be able to instantiate multiple Ai instances with ease to allow for multiple Ai players to be playing simultaneously.

Once I work on this some more, I plan to handle the mentioned exceptions that should be thrown, as well as begin working on creating some unique cards. For now I like the "make next player skip their turn" and "wild card". The wild card would allow the player to switch the current suit to any suit desired.

Here is a .exe in case you wanted to play the game ^^
http://download510.mediafire.com/13dumzc1bodg/awtwokn2wmt/Cards1.7z

Thursday, April 15, 2010

Card Simulation

Lately I have been documenting my experience with creating a deck simulator here, which is being written with Python 2.5.6.


I plan to continue documenting my progress at the link above, as well as on this blog. I posted the above link so that anyone that would like to can see all previous posts I've made up to my current point of development, which will be explained throughout this post.


I have chosen to create a card game called MauMau. MauMau is a game very similar to Uno, the main difference being that MauMau is played with a traditional deck of cards.


I currently have created a card class, deck class, MauMau class, and hand class. I manipulate these within the main function, which is the game loop. I also have created a function for determining if a player move is a valid move.


My immediate plans for the game is to:


- Create the used stack pile.
- Allow players to make a move by playing a card onto the used stack pile.
- Create an Ai which plays available cards, and draws if unavailable.
- Create rules for unique cards, like lose a turn, etc.



Here is my current build:


"""
To do:
- Create the used stack pile.
- Allow players to make a move by playing a card onto the used stack pile.
- Create an Ai which plays available cards, and draws if unavailable.
- Create rules for unique cards, like lose a turn, etc.

Created by: CecilSunkure
"""

import sys
import random

ACES_HIGH = True
GAME_RUNNING = True

class card:
    suits = ["Clubs",
             "Diamonds",
             "Hearts",
             "Spades" ]
    ranks = ["Ace",
             "2",
             "3",
             "4",
             "5",
             "6",
             "7",
             "8",
             "9",
             "10",
             "Jack",
             "Queen",
             "King" ]

    def __init__(self, suit=0, rank=0):
        self.suit = suit
        self.rank = rank

    def __str__(self):
        return (self.ranks[self.rank] + " of " + self.suits[self.suit])

class deck:
    def __init__(self):
        self.cards = []
        for suit in range(4):
            for rank in range(12):
                self.cards.append(card(suit, rank))

    def __str__(self):
        s = ''
        for i in range(len(self.cards)):
            s = s + str(self.cards[i]) + '\n'
        return s
          

    def shuffle(self):
        import random
        cards_length = len(self.cards)
        for i in range(cards_length):
            j = random.randrange(i, cards_length)
            self.cards[i], self.cards[j] = self.cards[j], self.cards[i]

    def remove(self, card):
        if card in self.cards:
            self.cards.remove(card)
            return True
        else:
            return False

    def draw(self):
        return self.cards.pop()

    def is_empty(self):
        return (len(self.cards) == 0)

    def deal(self, hands, num_cards=999):
        for i in range(num_cards):
            if self.is_empty(): break
            card = self.pop()
            hand = hands[i % len(hands)]
            hand.add(card)

    def pop(self):
        return self.cards.pop()


class hand(deck):
    def __init__(self, player=''):
        self.cards = []
        self.player = player

    def add(self, card):
        self.cards.append(card)

    def __str__(self):
        s = self.player + "'s Hand"
        t = 0
        if self.is_empty():
            s = s + " is empty\n"
        else:
            s = s + " contains\n"
        for i in range(len(self.cards)):
            t += 1
            s = s + str(t) + '. ' + str(self.cards[i]) + '\n'
        return s

class MauMau:
    def __init__(self, stack=0, topCard=0):
        self.deck = deck()
        self.deck.shuffle()
        self.players = []
        self.stack = stack
        self.topCard = topCard

    def getName(self):
        print('Welcome to Mau Mau!')
        player = raw_input()
        print('What is your name?')
        player = raw_input()
        print('')
        return player

    def startCard(self):
        self.topCard = self.deck.pop()

    def cmp_topCard(self, other):
        if self.topCard.suit == other.suit:
            if self.topCard.rank == other.rank:
                return True

def isValidMove(move, hand, game, handlen):
    """Used to determine if a move by checking to see if the move is an integer, followed by and testing to see
    if the proposed move is within the length of the hand passed to this function. Finally, this function
    makes sure that the proposed card to be played is valid within the rules of the game (same rank)."""
    x = []
    for i in range(1, (handlen+2)):
        x.append(i)
  
    try:
        int(move)
    except:
        print('That is not a valid move (not int).\n')
        return False

    if int(move) not in x:
        print('That is not a valid move (not 1-' + str(handlen+1) + ').\n')
        return False

    if move != str(handlen+1):
        if game.topCard.rank == hand.cards[(int(move)-1)].rank:
            return True
        else:
            return False
    elif move == str(handlen+1):
        return True

def main():
    """This function is the main loop used for running the Class MauMau. The turns between Ai and human are
    represented by integers, and those integers are used in if statements to determine which player is currently
    taking their turn."""
    #turn = random.randrange(2) + 1 <-- A comment for now, so for testing the human always goes.
    turn = 0
    game = MauMau()
    name = game.getName()
    hand1 = hand(name)
    hand2 = hand("CPU")
    game.deck.deal([hand1], 5)
    game.deck.deal([hand2], 5)
    game.startCard()
  
    if turn == 1:
        print('The computer will go first, as decided at random.')
    else:
        print('You will move first, as decided at random.')
  
    while GAME_RUNNING:
        print ('///' + '\n' + '/// ' + str(game.topCard) + '\n' + '///' + '\n')
        print (hand1)

        if turn == 1:
            print ('The computer will now take its turn, hit enter to proceed.')
            Move = raw_input()
        else:
            print ('Choose a card to play (1-' + str(len(hand1.cards)) + ') or draw a card (' + str((len(hand1.cards)+1)) + ').')
            Move = raw_input()

            if isValidMove(Move, hand1, game, len(hand1.cards)):
                print('Valid move check passed.\n')

                if Move == str(len(hand1.cards)+1):
                    hand1.add(game.deck.draw())
            else:
                print('Valid move check failed.\n')
              

if __name__ == "__main__":
    main()


In order to use the stack of cards for the face up cards that were already played, I plan to implement a common stack. A stack would be a list or array that is used to grab values out of in the order of the last appended first. I created a test module (.py file) before actually using it in the game. I have yet to implement something similar, but the source for this test is here:

 #A test module for creating a stack.

run = True
stack = []

while run:
    print('Stack, Pop, end, or continue? (1, 2, 3, enter)')
    yesno = raw_input()

    if yesno == '1':
        print('Enter a value to stack')
        a = raw_input()
        stack.append(a)

    if yesno == '2':
        try:
            stack.pop()
            b = stack.pop()
            print(b)
        except:
            print('Stack is empty.\n')

    if yesno == '3':
        run = False


    
Development is moving at a decent pace. Most of the time I am debugging the code I have written, but I am learning a ton. I've become very much more familiar with object orientation through the use of all my classes, and this project is definitely helping to enhance my overall coding ability. It's really pretty exciting :)

Here is a link to a .exe of my current build: http://download503.mediafire.com/m5ydqyl9zzng/nyfzyamykzi/Cards.7z