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.
| 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()

 Download
Download Copy to clipboard
Copy to clipboard

To fix the IndexError replace lines 156-157 with:
A index was needed for insert too - That should make the scores sorted well from lowest to highest.