Welcome, guest | Sign In | My Account | Store | Cart

As the final version of the War Game, development finally came to a halt as the prototype exceeded it bounds for design. Yes, you can write your program as one large function, but should you? This recipe demonstrates that program without proper style can lead to a mess very quickly. Practice good coding standards, or you can easily loose focus and the ability to maintain your code.

Python, 175 lines
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
from random import randint, seed
from time import time
# region: change
# from window import *
from Zpaw import *
from cards import *
card_list = [card_0, card_1, card_2, card_3, card_4, card_5, card_6, card_7, card_8, card_9]
# endregion

# page & window dimensions have been corrected.
def game():
    print 'Welcome to WAR V6!'
    print
    asking = True
    while asking:
        try:
            players = int(raw_input('How many players are there? '))
            if players < 2:
                print 'There must be at least two players.'
            else:
                asking = False
        except:
            print 'You must enter a number.'
    print
    names = []
    # region: change
    longest_name = 0
    for name in range(players):
        names.append(raw_input('What is the name of player ' + str(name + 1) + '? '))
        if len(names[-1]) > longest_name:
            longest_name = len(names[-1])
    # endregion
    deck = []
    for card in range(10):
        for player in range(players):
            deck.append(card)
    hands = []
    seed(time())
    for player in range(players):
        hand = ([], [])
        for card in range(10):
            index = randint(0, len(deck) - 1)
            hand[0].append(deck[index])
            del deck[index]
        hand[0].sort()
        hands.append(hand)
    for round in range(1, 11):
        table = []
        will_play = []
        high_card = 0
        for player in range(players):
            will_play.append(player)
        for turn in range(players):
            for line in range(50):
                print
            index = randint(0, len(will_play) - 1)
            now_play = will_play[index]
            del will_play[index]
            print 'Round', round
            raw_input('It is ' + names[now_play] + "'s turn to play.")
            print
            # region: change
            if len(table) == 0:
                print 'There are no cards on the table.\n'
            else:
                table_window = window(longest_name + 13, len(table) * 6)
                for card in range(len(table)):
                    # name_page = page(1, len(names[table[card][0]]) + 9)
                    # name_page.mutate(0, 0, names[table[card][0]] + ' played')
                    # table_window.append(name_page, [card * 6, 0])
                    # table_window.append(card_list[table[card][1]], [card * 6, len(names[table[card][0]]) + 8])
                    # table_window += struct(True, card * 6, 0, name_page)
                    # table_window += struct(True, card * 6, len(names[table[card][0]]) + 8, card_list[table[card][1]])
                    table_window += page(len(names[table[card][0]]) + 9, 1) \
                                    .mutate(0, 0, names[table[card][0]] + ' played').y(card * 6)
                    table_window += page(0, 0).link(card_list[table[card][1]]) \
                                    .x(len(names[table[card][0]]) + 8).y(card * 6)
                print table_window
            print 'These are your playing cards:'
            playing_window = window(len(hands[now_play][0]) * 6, 7)
            for index in range(len(hands[now_play][0])):
                # playing_window.append(card_list[hands[now_play][0][index]], [1, index * 6 + 1])
                # playing_window += struct(True, 1, index * 6 + 1, card_list[hands[now_play][0][index]])
                playing_window += page(0, 0).link(card_list[hands[now_play][0][index]]).x(index * 6 + 1).y(1)
            print playing_window
            if len(hands[now_play][1]) > 0:
                hands[now_play][1].sort()
                print 'These are your captured cards:'
                capture_window = window(len(hands[now_play][1]) * 6, 7)
                for index in range(len(hands[now_play][1])):
                    # capture_window.append(card_list[hands[now_play][1][index]], [1, index * 6 + 1])
                    # capture_window += struct(True, 1, index * 6 + 1, card_list[hands[now_play][1][index]])
                    capture_window += page(0, 0).link(card_list[hands[now_play][1][index]]).x(index * 6 + 1).y(1)
                print capture_window
            # endregion
            asking = True
            while asking:
                try:
                    card = int(raw_input('What card do you want to play? '))
                    if card >= 0 and card <= 9:
                        try:
                            hands[now_play][0].remove(card)
                            table.append((now_play, card))
                            if card > high_card:
                                high_card = card
                            asking = False
                        except:
                            print 'You do not have that card.'
                    else:
                        print 'You must enter a value between -1 and 10.'
                except:
                    print 'You must enter a number.'
        for line in range(50):
            print
        #region: change
        table_window = window(longest_name + 13, len(table) * 6)
        for card in range(len(table)):
            # name_page = page(1, len(names[table[card][0]]) + 9)
            # name_page.mutate(0, 0, names[table[card][0]] + ' played')
            # table_window.append(name_page, [card * 6, 0])
            # table_window.append(card_list[table[card][1]], [card * 6, len(names[table[card][0]]) + 8])
            # table_window += struct(True, card * 6, 0, name_page)
            # table_window += struct(True, card * 6, len(names[table[card][0]]) + 8, card_list[table[card][1]])
            table_window += page(len(names[table[card][0]]) + 9, 1) \
                            .mutate(0, 0, names[table[card][0]] + ' played').y(card * 6)
            table_window += page(0, 0).link(card_list[table[card][1]]) \
                            .x(len(names[table[card][0]]) + 8).y(card * 6)
        print table_window
        # endregion
        hand_out = []
        for index in range(players):
            if table[index][1] == high_card:
                hand_out.append(table[index][0])
        while len(table) > 0:
            hands[hand_out[randint(0, len(hand_out) - 1)]][1].append(table[0][1])
            del table[0]
        for player in range(players):
            if len(hands[player][1]) > 0:
                   print names[player] + ' has captured ' + str(len(hands[player][1])) + ' cards.'
        print
        raw_input('End Of Round ' + str(round))
    for line in range(50):
        print
    high_score = 0
    scores = []
    for player in range(players):
        total = 0
        for card in range(len(hands[player][1])):
            total += hands[player][1][card]
        if total > high_score:
            high_score = total
        if len(scores) == 0 or scores[len(scores) - 1][1] <= total:
            scores.append((player, total))
        else:
            for index in range(len(scores)):
                if total > scores[index][1]:
                    scores.insert((player, total))
                    break
    try:
        for player in range(players):
            # Next line of code has a problem (IndexError).
            print names[scores[player][0]] + ' received ' + str(scores[player][1]) + ' points.'
        print
        for index in range(10):
            raw_input('GAME OVER ... ' + str(9 - index))
    except Exception, bug:
        print
        print 'Oops!'
        print '\t', bug
        raw_input()

# NOTE:
# Am considering re-writing this game.
if __name__ == '__main__':
    game()

You will need the following files to run the program listed up above.

cards.py

import Zpaw

# Card definitions are simpler that before.
card_0 = Zpaw.page(5, 5).mutate(0, 0, '+---+').mutate(1, 0, '|   |').mutate(2, 0, '| 0 |').mutate(3, 0, '|   |').mutate(4, 0, '+---+')
card_1 = Zpaw.page(0, 0).link(card_0).unlink().mutate(2, 2, '1')
card_2 = Zpaw.page(0, 0).link(card_0).unlink().mutate(2, 2, '2')
card_3 = Zpaw.page(0, 0).link(card_0).unlink().mutate(2, 2, '3')
card_4 = Zpaw.page(0, 0).link(card_0).unlink().mutate(2, 2, '4')
card_5 = Zpaw.page(0, 0).link(card_0).unlink().mutate(2, 2, '5')
card_6 = Zpaw.page(0, 0).link(card_0).unlink().mutate(2, 2, '6')
card_7 = Zpaw.page(0, 0).link(card_0).unlink().mutate(2, 2, '7')
card_8 = Zpaw.page(0, 0).link(card_0).unlink().mutate(2, 2, '8')
card_9 = Zpaw.page(0, 0).link(card_0).unlink().mutate(2, 2, '9')
card_10 = Zpaw.page(0, 0).link(card_0).unlink().mutate(2, 1, '1 0')
card_A = Zpaw.page(0, 0).link(card_0).unlink().mutate(2, 2, 'A')
card_J = Zpaw.page(0, 0).link(card_0).unlink().mutate(2, 2, 'J')
card_Q = Zpaw.page(0, 0).link(card_0).unlink().mutate(2, 2, 'Q')
card_K = Zpaw.page(0, 0).link(card_0).unlink().mutate(2, 2, 'K')

# Test what the cards look like.
def main():
    print card_0
    print card_1
    print card_2
    print card_3
    print card_4
    print card_5
    print card_6
    print card_7
    print card_8
    print card_9
    print card_10
    print card_A
    print card_J
    print card_Q
    print card_K

# Test this module.
if __name__ == '__main__':
    main()

Zam.py

# Name & Description
# ==================

'''Support module for array and matrix use.

This module provides two classes that emulate one and two
dimentional lists with fixed sizes but mutable internals.'''

# Data & Imports
# ==============

__all__ = ['array', 'matrix']
__version__ = '1.1'

import sys

# Public Names
# ============

class array(object):

    '''array(length) -> new array
    array(length, value) -> initialized from value'''

    def __init__(self, length, value=None):
        '''x.__init__(...) initializes x'''
        self.__data = range(length)
        for index in range(length):
            self.__data[index] = value

    def __repr__(self):
        '''x.__repr__() <==> repr(x)'''
        return repr(self.__data)

    def __len__(self):
        '''x.__len__() <==> len(x)'''
        return len(self.__data)

    def __getitem__(self, key):
        '''x.__getitem__(y) <==> x[y]'''
        return self.__data[key]

    def __setitem__(self, key, value):
        '''x.__setitem__(i, y) <==> x[i]=y'''
        self.__data[key] = value

    def __delitem__(self, key):
        '''x.__delitem__(y) <==> del x[y]'''
        self.__data[key] = None

    def __iter__(self):
        '''x.__iter__() <==> iter(x)'''
        return iter(self.__data)

    def __contains__(self, value):
        '''x.__contains__(y) <==> y in x'''
        return value in self.__data

class matrix(object):

    '''matrix(rows, columns) -> new matrix
    matrix(rows, columns, value) -> initialized from value'''

    def __init__(self, rows, columns, value=None):
        '''x.__init__(...) initializes x'''
        self.__data = array(rows)
        for index in range(rows):
            self.__data[index] = array(columns, value)

    def __repr__(self):
        '''x.__repr__() <==> repr(x)'''
        return repr(self.__data)

    def __len__(self):
        '''x.__len__() <==> len(x)'''
        return len(self.__data)

    def __getitem__(self, key):
        '''x.__getitem__(y) <==> x[y]'''
        return self.__data[key]

    def __setitem__(self, key, value):
        '''x.__setitem__(i, y) <==> x[i]=y'''
        self.__data[key] = array(len(self.__data[key]), value)

    def __delitem__(self, key):
        '''x.__delitem__(y) <==> del x[y]'''
        self.__data[key] = array(len(self.__data[key]))

    def __iter__(self):
        '''x.__iter__() <==> iter(x)'''
        return iter(self.__data)

    def __contains__(self, value):
        '''x.__contains__(y) <==> y in x'''
        for item in self.__data:
            if value in item:
                return True
        return False

# Private Names
# =============

def main():
    print 'Content-Type: text/plain'
    print
    print file(sys.argv[0]).read()

# Execute Main
# ============

if __name__ == '__main__':
    main()

Zpaw.py

import Zam

class ClassError(StandardError): # VERSION 1.0
    pass # This class is just for exceptions.

class page(object): # VERSION 1.3

    def __init__(self, width, height, value=None):
        self.__assert_type((int, height), (int, width))
        if value is None:
            value = ''
        else:
            self.__assert_type((str, value))
        if value:
            self.__data = Zam.matrix(height, width, value[0])
        else:
            self.__data = Zam.matrix(height, width, ' ')
        self.__visible = True
        self.__x = 0
        self.__y = 0

    def __repr__(self):
        return repr(self.__data)

    def __str__(self):
        return '\n'.join([''.join(row) for row in self.__data])

    def width(self):
        return len(self.__data[0])

    def height(self):
        return len(self.__data)

    def access(self, row, column, length=None):
        self.__assert_type((int, row), (int, column))
        if length is None:
            length = 1
        else:
            self.__assert_type((int, length))
        string = str()
        for index in range(length):
            try:
                string += self.__data[row][column + index]
            except:
                pass
        return string

    def mutate(self, row, column, value):
        self.__assert_type((int, row), (int, column), (str, value))
        for index in range(len(value)):
            try:
                self.__data[row][column + index] = value[index]
            except:
                pass
        return self

    def set_row(self, row, value=None):
        self.__assert_type((int, row))
        if value is None:
            value = ''
        else:
            self.__assert_type((str, value))
        if value:
            self.__data[row] = value[0]
        else:
            self.__data[row] = ' '
        return self

    def set_column(self, column, value=None):
        self.__assert_type((int, column))
        if value is None:
            value = ''
        else:
            self.__assert_type((str, value))
        for row in self.__data:
            if value:
                row[column] = value[0]
            else:
                row[column] = ' '
        return self

    def visible(self, value=None):
        if value is None:
            return self.__visible
        else:
            self.__assert_type((bool, value))
            self.__visible = value
            return self

    def x(self, value=None):
        if value is None:
            return self.__x
        else:
            self.__assert_type((int, value))
            self.__x = value
            return self

    def y(self, value=None):
        if value is None:
            return self.__y
        else:
            self.__assert_type((int, value))
            self.__y = value
            return self

    def page(self, ids=None): # ids=None is for recursion bug fix.
        return self

    def _page(self): # This functions is for recursion bug fix.
        return self

    def project(self, value): # Does not respect value.visible().
        self.__assert_class((page, value))
        for row in range(value.height()):
            for column in range(value.width()):
                try:
                    self.__data \
                                [row + value.y()] \
                                [column + value.x()] = \
                                value.__data[row][column]
                except:
                    pass
        return self

    def link(self, value): # Loses current matrix and uses value's.
        self.__assert_class((page, value))
        self.__data = value.__data
        return self

    def unlink(self): # Copies and unlinks current matrix.
        temp = Zam.matrix(self.height(), self.width())
        for row in range(self.height()):
            for column in range(self.width()):
                temp[row][column] = self.__data[row][column]
        self.__data = temp
        return self

    def __assert_class(self, *tuples):
        for classes, objects in tuples:
            if objects.__class__ is not classes:
                raise ClassError(str(objects.__class__) + ' is not ' + str(classes))

    def __assert_type(self, *tuples):
        for types, objects in tuples:
            if type(objects) is not types:
                raise TypeError

class window(object): # VERSION 1.7

    def __init__(self, width, height, border=None, background=None):
        self.__assert_type((int, width), (int, height))
        if border is None:
            border = ''
        else:
            self.__assert_type((str, border))
        if background is None:
            background = ''
        else:
            self.__assert_type((str, background))
        self.__width = width
        self.__height = height
        if border:
            self.__border = border[0]
        else:
            self.__border = None
        if background:
            self.__background = background[0]
        else:
            self.__background = ' '
        self.__list = list()
        # __page must exist for __refresh.
        self.__page = page(0, 0)
        self.__refresh()


    def __repr__(self):
        self.__refresh()
        return repr(self.__page)

    def __str__(self):
        self.__refresh()
        return str(self.__page)

    def width(self, value=None):
        if value is None:
            return self.__width
        else:
            self.__assert_type((int, value))
            self.__width = value
            return self

    def height(self, value=None):
        if value is None:
            return self.__height
        else:
            self.__assert_type((int, value))
            self.__height = value
            return self

    def border(self, value=None):
        if value is None:
            return self.__border
        else:
            self.__assert_type((str, value))
            if value:
                self.__border = value[0]
            else:
                self.__border = None
            return self

    def background(self, value=None):
        if value is None:
            return self.__background
        else:
            self.__assert_type((str, value))
            if value:
                self.__background = value[0]
            else:
                self.__background = ' '
            return self

    def __len__(self):
        return len(self.__list)

    def __getitem__(self, key):
        self.__assert_type((int, key))
        return self.__list[key]

    def __setitem__(self, key, value):
        self.__assert_type((int, key))
        self.__assert_class((page, window, value))
        self.__list[key] = value

    def __delitem__(self, key):
        self.__assert_type((int, key))
        del self.__list[key]

    def __iter__(self):
        return iter(self.__list)

    def __contains__(self, value):
        self.__assert_class((page, window, value))
        return value in self.__list

    def __iadd__(self, value):
        self.__assert_class((page, window, value))
        self.__list.append(value)
        return self # Must return self.

    def __isub__(self, value):
        self.__assert_class((page, window, value))
        while value in self.__list:
            self.__list.remove(value)
        return self # Must return self.

    def visible(self, value=None):
        if value is None:
            return self.__page.visible()
        else:
            # Check type here and return self.
            self.__assert_type((bool, value))
            self.__page.visible(value)
            return self

    def x(self, value=None):
        if value is None:
            return self.__page.x()
        else:
            # Check type here and return self.
            self.__assert_type((int, value))
            self.__page.x(value)
            return self

    def y(self, value=None):
        if value is None:
            return self.__page.y()
        else:
            # Check type here and return self.
            self.__assert_type((int, value))
            self.__page.y(value)
            return self

    def page(self, ids=None):
        # ids=None helps prevent too much recursion.
        if ids is not None:
            self.__assert_type((list, ids))
        self.__refresh(ids)
        return self.__page

    def _page(self): # Don't refresh __page.
        return self.__page

    def __refresh(self, ids=None):
        if ids is None:
            ids = list()
        # region: should not be executed if id(self) in ids.
        temp = page(self.__width, self.__height, self.__background) \
               .visible(self.__page.visible()).x(self.__page.x()).y(self.__page.y())
        self.__page = temp
        for item in self.__list:
            if item.visible():
                # This needs to be fixed.
                if id(item) in ids:
                    self.__page.project(item._page())
                else:
                    ids.append(id(item))
                    self.__page.project(item.page(ids))
        # endregion
        # The border still needs to finished.
        # Border needs be finished for caller and projection.
        if self.__border:
            self.__page \
                        .set_row(0, self.__border).set_row(self.__height - 1, self.__border) \
                        .set_column(0, self.__border).set_column(self.__width - 1, self.__border)

    def __assert_class(self, *tuples):
        # This function allows checking against several classes.
        # Note: self.__assert_class((class, ..., object), ...)
        for objects in tuples:
            for classes in objects[:-1]:
                if objects[-1].__class__ is classes:
                    break
            if objects[-1].__class__ is not classes:
                raise ClassError

    def __assert_type(self, *tuples):
        # Allows checking against only one type per object.
        # Note: self.__assert_type((type, object), ...)
        for types, objects in tuples:
            if type(objects) is not types:
                raise TypeError

# TEST CODE

def main():
    # PART 1
    print 'PART 1'
    it = window(10, 10)
    print it
    print it.border('#')
    print it.background('-')
    it += page(1, 1, '%').x(2).y(2)
    print it
    other = page(2, 2, 'H')
    it += other.x(3).y(3)
    print it
    it -= other
    print it
    del it[0]
    print it
    other = page(2, 2, '%')
    it += other.x(2).y(2)
    print it
    other_2 = page(0, 0)
    it += other_2.y(5).x(2).link(other)
    print it
    other_2.mutate(0, 0, 'H')
    print it
    print it.border('').background('')
    # PART 2
    print 'PART 2'
    test = window(40, 20, '#', '.')
    print test
    copy = page(0, 0).link(test.page())
    test += page(5, 5).mutate(0, 0, '+---+').mutate(1, 0, '|   |')
    print test
    test += page(0, 0).link(test[0].x(3).y(2)).x(3).y(11)
    print test
    test[1].mutate(2, 0, '| A |').mutate(3, 0, test[0].access(1, 0, 5))
    print test
    test[0].mutate(4, 0, test[1].access(0, 0, 5))
    print test
    test[0].visible(False)
    print test
    test[0].mutate(2, 2, 'B')
    print test
    test[0].visible(True)
    test[1].visible(False)
    print test
    test.height(10).width(20)[1] =  page(3, 3, 'X').x(6).y(5)
    print test
    print copy
    # PART 3 - recursion depth fix
    print 'PART 3'
    try:
        test += test
        print test
        print test.x(5).y(5)
        # NOTE: border cannot be shown with recusion
    except RuntimeError, bug:
        print 'TEST FAILED:', bug

if __name__ == '__main__':
    main()

1 comment

Yoni Messica 8 years, 11 months ago  # | flag

To fix the IndexError replace lines 156-157 with:

            if total < scores[index][1]:
                scores.insert(index, (player, total))

A index was needed for insert too - That should make the scores sorted well from lowest to highest.