Sei sulla pagina 1di 53

Supply and demand is perhaps one of the most fundamental concepts of

economics and it is the backbone of a market economy. Demand refers to


how much (quantity) of a product or service is desired by buyers. The quantity
demanded is the amount of a product people are willing to buy at a certain
price; the relationship between price and quantity demanded is known as the
demand relationship. Supply represents how much the market can offer. The
quantity supplied refers to the amount of a certain good producers are willing
to supply when receiving a certain price. The correlation between price and
how much of a good or service is supplied to the market is known as the
supply relationship. Price, therefore, is a reflection of supply and demand.

Supply schedule[edit]
A supply schedule is a table that shows the relationship between the price of a good and the
quantity supplied. Under the assumption of perfect competition, supply is determined by marginal
cost. That is, firms will produce additional output while the cost of producing an extra unit of
output is less than the price they would receive.

Demand schedule[edit]
A demand schedule, depicted graphically as the demand curve, represents the amount of
some goods that buyers are willing and able to purchase at various prices, assuming all
determinants of demand other than the price of the good in question, such as income, tastes and
preferences, the price of substitute goods, and the price of complementary goods, remain the
same. Following the law of demand, the demand curve is almost always represented as
downward-sloping, meaning that as price decreases, consumers will buy more of the good. [1]

A. The Law of Demand


The law of demand states that, if all other factors remain equal, the higher the price
of a good, the less people will demand that good. In other words, the higher the
price, the lower the quantity demanded. The amount of a good that buyers purchase
at a higher price is less because as the price of a good goes up, so does the
opportunity cost of buying that good. As a result, people will naturally avoid buying a
product that will force them to forgo the consumption of something else they value
more. The chart below shows that the curve is a downward slope.

A, B and C are points on the demand curve. Each point on the curve reflects a direct
correlation between quantity demanded (Q) and price (P). So, at point A, the quantity
demanded will be Q1 and the price will be P1, and so on. The demand relationship
curve illustrates the negative relationship between price and quantity demanded. The
higher the price of a good the lower the quantity demanded (A), and the lower the
price, the more the good will be in demand (C).

B. The Law of Supply


Like the law of demand, the law of supply demonstrates the quantities that will be
sold at a certain price. But unlike the law of demand, the supply relationship shows
an upward slope. This means that the higher the price, the higher the quantity
supplied. Producers supply more at a higher price because selling a higher quantity
at a higher price increases revenue.
A, B and C are points on the supply curve. Each point on the curve reflects a direct
correlation between quantity supplied (Q) and price (P). At point B, the quantity
supplied will be Q2 and the price will be P2, and so on. (To learn how economic
factors are used in currency trading, read Forex Walkthrough: Economics.)

Time and Supply


Unlike the demand relationship, however, the supply relationship is a factor of time.
Time is important to supply because suppliers must, but cannot always, react quickly
to a change in demand or price. So it is important to try and determine whether a
price change that is caused by demand will be temporary or permanent.

Let's say there's a sudden increase in the demand and price for umbrellas in an
unexpected rainy season; suppliers may simply accommodate demand by using
their production equipment more intensively. If, however, there is a climate change,
and the population will need umbrellas year-round, the change in demand and price
will be expected to be long term; suppliers will have to change their equipment and
production facilities in order to meet the long-term levels of demand.

C. Supply and Demand Relationship


Now that we know the laws of supply and demand, let's turn to an example to show
how supply and demand affect price.

Imagine that a special edition CD of your favorite band is released for $20. Because
the record company's previous analysis showed that consumers will not demand
CDs at a price higher than $20, only ten CDs were released because the opportunity
cost is too high for suppliers to produce more. If, however, the ten CDs are
demanded by 20 people, the price will subsequently rise because, according to the
demand relationship, as demand increases, so does the price. Consequently, the
rise in price should prompt more CDs to be supplied as the supply relationship
shows that the higher the price, the higher the quantity supplied.

If, however, there are 30 CDs produced and demand is still at 20, the price will not
be pushed up because the supply more than accommodates demand. In fact after
the 20 consumers have been satisfied with their CD purchases, the price of the
leftover CDs may drop as CD producers attempt to sell the remaining ten CDs. The
lower price will then make the CD more available to people who had previously
decided that the opportunity cost of buying the CD at $20 was too high.

D. Equilibrium
When supply and demand are equal (i.e. when the supply function and demand
function intersect) the economy is said to be at equilibrium. At this point, the
allocation of goods is at its most efficient because the amount of goods being
supplied is exactly the same as the amount of goods being demanded. Thus,
everyone (individuals, firms, or countries) is satisfied with the current economic
condition. At the given price, suppliers are selling all the goods that they have
produced and consumers are getting all the goods that they are demanding.
As you can see on the chart, equilibrium occurs at the intersection of the demand
and supply curve, which indicates no allocative inefficiency. At this point, the price of
the goods will be P* and the quantity will be Q*. These figures are referred to as
equilibrium price and quantity.

In the real market place equilibrium can only ever be reached in theory, so the prices
of goods and services are constantly changing in relation to fluctuations in demand
and supply.

E. Disequilibrium

Disequilibrium occurs whenever the price or quantity is not equal to P* or Q*.

1. Excess Supply
If the price is set too high, excess supply will be created within the economy and
there will be allocative inefficiency.

At price P1 the quantity of goods that the producers wish to supply is indicated by
Q2. At P1, however, the quantity that the consumers want to consume is at Q1, a
quantity much less than Q2. Because Q2 is greater than Q1, too much is being
produced and too little is being consumed. The suppliers are trying to produce more
goods, which they hope to sell to increase profits, but those consuming the goods
will find the product less attractive and purchase less because the price is too high.

2. Excess Demand
Excess demand is created when price is set below the equilibrium price. Because
the price is so low, too many consumers want the good while producers are not
making enough of it.

In this situation, at price P1, the quantity of goods demanded by consumers at this
price is Q2. Conversely, the quantity of goods that producers are willing to produce
at this price is Q1. Thus, there are too few goods being produced to satisfy the wants
(demand) of the consumers. However, as consumers have to compete with one
other to buy the good at this price, the demand will push the price up, making
suppliers want to supply more and bringing the price closer to its equilibrium.

F. Shifts vs. Movement


For economics, the "movements" and "shifts" in relation to the supply and demand
curves represent very different market phenomena:

1. Movements
A movement refers to a change along a curve. On the demand curve, a movement
denotes a change in both price and quantity demanded from one point to another on
the curve. The movement implies that the demand relationship remains consistent.
Therefore, a movement along the demand curve will occur when the price of the
good changes and the quantity demanded changes in accordance to the original
demand relationship. In other words, a movement occurs when a change in the
quantity demanded is caused only by a change in price, and vice versa.
Like a movement along the demand curve, a movement along the supply curve
means that the supply relationship remains consistent. Therefore, a movement along
the supply curve will occur when the price of the good changes and the quantity
supplied changes in accordance to the original supply relationship. In other words, a
movement occurs when a change in quantity supplied is caused only by a change in
price, and vice versa.

2. Shifts
A shift in a demand or supply curve occurs when a good's quantity demanded or
supplied changes even though price remains the same. For instance, if the price for
a bottle of beer was $2 and the quantity of beer demanded increased from Q1 to Q2,
then there would be a shift in the demand for beer. Shifts in the demand curve imply
that the original demand relationship has changed, meaning that quantity demand is
affected by a factor other than price. A shift in the demand relationship would occur
if, for instance, beer suddenly became the only type of alcohol available for
consumption.
Conversely, if the price for a bottle of beer was $2 and the quantity supplied
decreased from Q1 to Q2, then there would be a shift in the supply of beer. Like a
shift in the demand curve, a shift in the supply curve implies that the original supply
curve has changed, meaning that the quantity supplied is effected by a factor other
than price. A shift in the supply curve would occur if, for instance, a natural disaster
caused a mass shortage of hops; beer manufacturers would be forced to supply less
beer for the same price.
Final Accounts are the accounts, which are prepared at the end of a fiscal
year. It gives a precise idea of the financial position of the
business/organization to the owners, management, or other interested
parties. Financial statements are primarily recorded in a journal; then
transferred to a ledger; and thereafter, the final account is prepared (as
shown in the illustration).

Usually, a final account includes the following components −

 Trading Account

 Manufacturing Account

 Profit and Loss Account

 Balance Sheet

Now, let us discuss each of them in detail −

Trading Account
Trading accounts represents the Gross Profit/Gross Loss of the concern
out of sale and purchase for the particular accounting period.

Study of Debit side of Trading Account


 Opening Stock − Unsold closing stock of the last financial year is appeared
in debit side of the Trading Account as “To Opening Stock“ of the current
financial year.

 Purchases − Total purchases (net of purchase return) including cash


purchase and credit purchase of traded goods during the current financial
year appeared as “To Purchases” in the debit side of Trading Account.

 Direct Expenses − Expenses incurred to bring traded goods at business


premises/warehouse called direct expenses. Freight charges, cartage or
carriage charges, custom and import duty in case of import, gas, electricity
fuel, water, packing material, wages, and any other expenses incurred in this
regards comes under the debit side of Trading Account and appeared as “To
Particular Name of the Expenses”.

 Sales Account − Total Sale of the traded goods including cash and credit
sales will appear at outer column of the credit side of Trading Account as “By
Sales.” Sales should be on net releasable value excluding Central Sales Tax,
Vat, Custom, and Excise Duty.
 Closing Stock − Total Value of unsold stock of the current financial year is
called as closing stock and will appear at the credit side of Trading Account.

closing Stock = Opening Stock + Net Purchases - Net Sale

 Gross Profit − Gross profit is the difference of revenue and the cost of
providing services or making products. However, it is
calculated before deducting payroll, taxation, overhead, and other interest
payments. Gross Margin is used in the US English and carries same meaning
as the Gross Profit.

Gross Profit = Sales - Cost of Goods Sold

 Operating Profit − Operating profit is the difference of revenue and the


costs generated by ordinary operations. However, it is
calculated before deducting taxes, interest payments, investment
gains/losses, and many other non-recurring items.

Operating Profit = Gross Profit - Total Operating Expenses

 Net Profit − Net profit is the difference of total revenue and the total
expenses of the company. It is also known as net income or net earnings.

Net Profit = Operating Profit - (Taxes + Interest)

Format of Trading Account


Trading Account of M/s ABC Limited

(For the period ending 31-03-2014)

Particulars Amount Particulars Amount

To Opening Stock XX By Sales XX

To Purchases XX By Closing Stock XX

To Direct Expenses XX By Gross Loss c/d XXX

To Gross Profit c/d XXX

Total XXXX Total XXXX


Manufacturing Account
Manufacturing account prepared in a case where goods are manufactured
by the firm itself. Manufacturing accounts represent cost of production.
Cost of production then transferred to Trading account where other
traded goods also treated in a same manner as Trading account.

Important Point Related to Manufacturing Account


Apart from the points discussed under the section of Trading account,
there are a few additional important points that need to be discuss here

 Raw Material − Raw material is used to produce products and there may be
opening stock, purchases, and closing stock of Raw material. Raw material is
the main and basic material to produce items.

 Work-in-Progress − Work-in-progress means the products, which are still


partially finished, but they are important parts of the opening and closing
stock. To know the correct value of the cost of production, it is necessary to
calculate the correct cost of it.

 Finished Product − Finished product is the final product, which is


manufactured by the concerned business and transferred to trading account
for sale.

 Raw Material Consumed (RMC) − It is calculated as.

RMC = Opening Stock of Raw Material + Purchases - Closing Stock

 Cost of Production − Cost of production is the balancing figure of


Manufacturing account as per the format given below.

Manufacturing Account

(For the year ending……….)

Particulars Amount Particulars Amount

To Opening Stock of Work-in- By Closing Stock of Work-in-


XX XX
Progress Progress

To Raw Material Consumed XX By Scrap Sale XX

To Wages XXX By Cost of Production XXX


To Factory overheadxx (Balancing figure)

Power or fuelxx

Dep. Of Plantxx

Rent- Factoryxx

Other Factory Exp.xx xxx

Total XXXX Total XXXX

Profit and Loss Account


Profit & Loss account represents the Gross profit as transferred from
Trading Account on the credit side of it along with any other income
received by the firm like interest, Commission, etc.

Debit side of profit and loss account is a summary of all the indirect
expenses as incurred by the firm during that particular accounting year.
For example, Administrative Expenses, Personal Expenses, Financial
Expenses, Selling, and Distribution Expenses, Depreciation, Bad Debts,
Interest, Discount, etc. Balancing figure of profit and loss accounts
represents the true and net profit as earned at the end of the accounting
period and transferred to the Balance Sheet.

Profit & Loss Account of M/s ………

(For the period ending ………..)

Particulars Amount Particulars Amount

To Salaries XX By Gross Profit b/d XX

To Rent XX

To Office Expenses XX By Bank Interest received XX


To Bank charges XX By Discount XX

To Bank Interest XX By Commission Income XX

By Net Loss transfer to


To Electricity Expenses XX XX
Balance sheet

To Staff Welfare Expenses XX

To Audit Fees XX

To Repair & Renewal XX

To Commission XX

To Sundry Expenses XX

To Depreciation XX

To Net Profit transfer to


XX
Balance sheet

Total XXXX Total XXXX

Balance Sheet
A balance sheet reflects the financial position of a business for the
specific period of time. The balance sheet is prepared by tabulating the
assets (fixed assets + current assets) and the liabilities (long term
liability + current liability) on a specific date.

Assets
Assets are the economic resources for the businesses. It can be
categorized as −

 Fixed Assets − Fixed assets are the purchased/constructed assets, used to


earn profit not only in current year, but also in next coming years. However,
it also depends upon the life and utility of the assets. Fixed assets may be
tangible or intangible. Plant & machinery, land & building, furniture, and
fixture are the examples of a few Fixed Assets.
 Current Assets − The assets, which are easily available to discharge current
liabilities of the firm called as Current Assets. Cash at bank, stock, and
sundry debtors are the examples of current assets.

 Fictitious Assets − Accumulated losses and expenses, which are not


actually any virtual assets called as Fictitious Assets. Discount on issue of
shares, Profit & Loss account, and capitalized expenditure for time being are
the main examples of fictitious assets.

 Cash & Cash Equivalents − Cash balance, cash at bank, and securities
which are redeemable in next three months are called as Cash & Cash
equivalents.

 Wasting Assets − The assets, which are reduce or exhausted in value


because of their use are called as Wasting Assets. For example, mines,
queries, etc.

 Tangible Assets − The assets, which can be touched, seen, and have
volume such as cash, stock, building, etc. are called as Tangible Assets.

 Intangible Assets − The assets, which are valuable in nature, but cannot
be seen, touched, and not have any volume such as patents, goodwill, and
trademarks are the important examples of intangible assets.

 Accounts Receivables − The bills receivables and sundry debtors come


under the category of Accounts Receivables.

 Working Capital − Difference between the Current Assets and the Current
Liabilities are called as Working Capital.

Liability
A liability is the obligation of a business/firm/company arises because of
the past transactions/events. Its settlement/repayments is expected to
result in an outflow from the resources of respective firm.

There are two major types of Liability −

 Current Liabilities − The liabilities which are expected to be liquidated by


the end of current year are called as Current Liabilities. For example, taxes,
accounts payable, wages, partial payments of long term loans, etc.

 Long-term Liabilities − The liabilities which are expected to be liquidated in


more than a year are called as Long-term Liabilities. For example,
mortgages, long-term loan, long-term bonds, pension obligations, etc.
Grouping of Assets and Liabilities
There may be two types of Marshalling and grouping of the assets and
liabilities −

 In order of Liquidity − In this case, assets and liabilities are arranged


according to their liquidity.

 In order of Permanence − In this case, order of the arrangement of assets


and liabilities are reversed as followed in order of liquidity.

MAR'18 MAR'17 YoY


Parameter
(₹ Cr.) (₹ Cr.) %Change
EQUITY AND LIABILITIES
Share Capital 6,335.00 3,251.00 94.86%
Share Warrants & Outstandings
Total Reserves 3,08,297.00 2,85,058.00 8.15%
Shareholder's Funds 3,14,647.00 2,88,313.00 9.13%
Long-Term Borrowings 0.00 0.00 0.00%
Secured Loans 500.00 1,003.00 -50.15%
Unsecured Loans 81,096.00 77,720.00 4.34%
Deferred Tax Assets / Liabilities 27,926.00 24,766.00 12.76%
Other Long Term Liabilities 504.00 0.00 100.00%
Long Term Trade Payables 0.00 0.00 0.00%
Long Term Provisions 2,205.00 2,118.00 4.11%
Total Non-Current Liabilities 1,12,231.00 1,05,607.00 6.27%
Current Liabilities
Trade Payables 88,675.00 68,161.00 30.10%
Other Current Liabilities 85,815.00 60,817.00 41.10%
Short Term Borrowings 15,239.00 22,580.00 -32.51%
Short Term Provisions 918.00 1,268.00 -27.60%
Total Current Liabilities 1,90,647.00 1,52,826.00 24.75%
Total Liabilities 6,17,525.00 5,46,746.00 12.95%
ASSETS
Non-Current Assets 0.00 0.00 0.00%
Gross Block 3,53,009.00 2,97,352.00 18.72%
Less: Accumulated Depreciation 1,52,045.00 1,42,774.00 6.49%
Less: Impairment of Assets 0.00 0.00 0.00%
Net Block 2,00,964.00 1,54,578.00 30.01%
Lease Adjustment A/c 0.00 0.00 0.00%
Capital Work in Progress 92,581.00 1,28,283.00 -27.83%
Intangible assets under development 6,902.00 4,458.00 54.82%
Pre-operative Expenses pending 0.00 0.00 0.00%
Assets in transit 0.00 0.00 0.00%
Non Current Investments 1,71,945.00 1,40,544.00 22.34%
Long Term Loans & Advances 19,659.00 12,286.00 60.01%
Other Non Current Assets 1,562.00 316.00 394.30%
Total Non-Current Assets 4,93,613.00 4,40,465.00 12.07%
Current Assets Loans & Advances
Currents Investments 53,277.00 51,906.00 2.64%
Inventories 39,568.00 34,018.00 16.31%
Sundry Debtors 10,460.00 5,472.00 91.15%
Cash and Bank 2,731.00 1,754.00 55.70%
Other Current Assets 8,999.00 3,601.00 149.90%
Short Term Loans and Advances 8,877.00 9,530.00 -6.85%
Total Current Assets 1,23,912.00 1,06,281.00 16.59%
Net Current Assets (Including Current Investments) -66,735.00 -46,545.00 43.38%
Total Current Assets Excluding Current Investments 70,635.00 54,375.00 29.90%
Miscellaneous Expenses not written off 0.00 0.00 0.00%
Total Assets 6,17,525.00 5,46,746.00 12.95%
Contingent Liabilities 57,973.00 59,378.00 -2.37%
Total Debt 1,16,881.00 1,07,446.00 8.78%
Book Value (in ₹) 496.66 886.83 -44.00%
Adjusted Book Value (in ₹) 496.66 443.42 12.01%

Particulars Mar'18 Mar'17 Mar'16 Mar'15 Mar'14

Liabilities 12 Months 12 Months 12 Months 12 Months 12 Months

Share Capital 1092.00 1148.00 1148.00 574.00 286.00

Reserves & Surplus 62410.00 66869.00 59934.00 47494.00 41806.00

Net Worth 63502.00 68017.00 61082.00 48068.00 42092.00

Secured Loan .00 .00 .00 .00 .00


Unsecured Loan .00 .00 .00 .00 .00

TOTAL LIABILITIES 63502.00 68017.00 61082.00 48068.00 42092.00

Assets

Gross Block 18079.00 16210.00 14709.00 12827.00 10374.00

(-) Acc. Depreciation 8922.00 7605.00 6461.00 5480.00 4642.00

Net Block 9157.00 8605.00 8248.00 7347.00 5732.00

Capital Work in Progress 1442.00 1247.00 934.00 769.00 954.00

Investments 17899.00 24977.00 11078.00 6857.00 6717.00

Inventories .00 .00 .00 .00 .00

Sundry Debtors 12151.00 10960.00 9798.00 8627.00 7336.00

Cash and Bank 16770.00 19153.00 29176.00 27722.00 24100.00

Loans and Advances 18458.00 14943.00 13498.00 10491.00 7873.00

Total Current Assets 47379.00 45056.00 52472.00 46840.00 39309.00

Current Liabilities 11939.00 11518.00 11214.00 5700.00 4503.00

Provisions 436.00 350.00 436.00 8045.00 6117.00

Total Current Liabilities 12375.00 11868.00 11650.00 13745.00 10620.00

NET CURRENT ASSETS 35004.00 33188.00 40822.00 33095.00 28689.00

Misc. Expenses .00 .00 .00 .00 .00

TOTAL ASSETS(A+B+C+D+E) 63502.00 68017.00 61082.00 48068.00 42092.00

Tic-tac-toe is a very popular game, so let’s implement an automatic


Tic-tac-toe game using Python.
The game is automatically played by the program and hence, no
user input is needed. Still, developing a automatic game will be lots
of fun. Let’s see how to do this.
numpyand random Python libraries are used to build this game. Instead of
asking the user to put a mark on the board, code randomly chooses
a place on the board and put the mark. It will display the board after
each turn unless a player wins. If the game gets draw, then it
returns -1.

Explanation :
play_game() is the main function, which performs following tasks :
 Calls create_board() to create a 9×9 board and initializes with 0.
 For each player (1 or 2), calls the random_place() function to randomly
choose a location on board and mark that location with the player number,
alternatively.
 Print the board after each move.
 Evaluate the board after each move to check whether a row or column or a
diagonal has the same player number. If so, displays the winner name. If after
9 moves, there are no winner then displays -1.
Below is the code for the above game :
# Tic-Tac-Toe Program using
# random number in Python

# importing all necessary libraries


import numpy as np
import random
from time import sleep

# Creates an empty board


def create_board():
return(np.array([[0, 0, 0],
[0, 0, 0],
[0, 0, 0]]))

# Check for empty places on board


def possibilities(board):
l = []

for i in range(len(board)):
for j in range(len(board)):

if board[i][j] == 0:
l.append((i, j))
return(l)

# Select a random place for the player


def random_place(board, player):
selection = possibilities(board)
current_loc = random.choice(selection)
board[current_loc] = player
return(board)

# Checks whether the player has three


# of their marks in a horizontal row
def row_win(board, player):
for x in range(len(board)):
win = True

for y in range(len(board)):
if board[x, y] != player:
win = False
continue

if win == True:
return(win)
return(win)

# Checks whether the player has three


# of their marks in a vertical row
def col_win(board, player):
for x in range(len(board)):
win = True

for y in range(len(board)):
if board[y][x] != player:
win = False
continue

if win == True:
return(win)
return(win)

# Checks whether the player has three


# of their marks in a diagonal row
def diag_win(board, player):
win = True

for x in range(len(board)):
if board[x, x] != player:
win = False
return(win)

# Evaluates whether there is


# a winner or a tie
def evaluate(board):
winner = 0

for player in [1, 2]:


if (row_win(board, player) or
col_win(board,player) or
diag_win(board,player)):

winner = player

if np.all(board != 0) and winner == 0:


winner = -1
return winner

# Main function to start the game


def play_game():
board, winner, counter = create_board(), 0, 1
print(board)
sleep(2)

while winner == 0:
for player in [1, 2]:
board = random_place(board, player)
print("Board after " + str(counter) + " move")
print(board)
sleep(2)
counter += 1
winner = evaluate(board)
if winner != 0:
break
return(winner)

# Driver Code
print("Winner is: " + str(play_game()))
Run on IDE

Output :
[[0 0 0]

[0 0 0]

[0 0 0]]

Board after 1 move

[[0 0 0]

[0 0 0]

[1 0 0]]

Board after 2 move

[[0 0 0]

[0 2 0]

[1 0 0]]

Board after 3 move

[[0 1 0]

[0 2 0]

[1 0 0]]

Board after 4 move

[[0 1 0]

[2 2 0]

[1 0 0]]

Board after 5 move

[[1 1 0]

[2 2 0]

[1 0 0]]

Board after 6 move

[[1 1 0]

[2 2 0]

[1 2 0]]

Board after 7 move

[[1 1 0]

[2 2 0]
[1 2 1]]

Board after 8 move

[[1 1 0]

[2 2 2]

[1 2 1]]

Winner is: 2

Handling two players


The p1() function resembles p2(), and the main loop contains two copies of code that is
mostly the same. check_board() also has some repetition. The root cause is the need to
associate Player 1 with the symbol X and the verbal description "cross", and Player 2
with the symbol O and the verbal description "nought". The code would be easier to
generalize if you just called them "Player X" and "Player O", and I think that the user
experience would be enhanced as well. (You could also generalize the code without
such a simplification by using, say, a namedtuple to represent each player.)
p1() and p2() could be simplified by moving the validation into choose_number(),
especially if you didn't care to distinguish between the "You can't go there" and "That's
not on the board" error messages.
Implementation details

 In choose_number(), there is no need for a nested while True. You also


don't need to write continue.
 Renaming check_board() to is_game_over() would make its purpose more
obvious
 win_commbinations contains a misspelling, and would be better
as WIN_COMBINATIONS to indicate that it is a constant. board[a[0]] ==
board[a[1]] == board[a[2]] is ugly, and would be better expressed as
 for a, b, c in WIN_COMBINATIONS:
 if board[a] == board[b] == board[c] …
 In check_board(), you used the variable a for two different purposes,
which is confusing. I would just rewrite the second half of the function
entirely as
 if 9 == sum((pos == 'X' or pos == 'O') for pos in board):
 print("The game ends in a tie\n")
 return True
 There is no need for the end variable. (In general, such flag variables
should be eliminated.)

Initialising board as containing integers that will then be replaced by strings is a bit off.
You're mixing types needlessly when you could just make these strings. It has no
functional difference but it's good to be in the mindset of keeping data consistent unless
you have a good reason to deviate.

draw is not well laid out at all. Instead of just plain printing arguments, use str.format.
That would make it easier to adjust how they're arranged, instead of just sticking with the
default result of using print with commas. This is how you could do it:
def draw():
print("{} {} {}\n{} {} {}\n {} {} {}\n".format(*board))
To explain, str.format will replace each {} with arguments passed to it. * is the
unpacking operator, that means that all the values from board are being unpacked and
passed. So you're actually passing the nine elements of the list, not the list itself.
Instead of board[n] == "X" or board[n] == "O" you can use board[n] in "XO".
The in keyword tests for if a value is in a string, list or other collection. It's often an
easier way of testing equality for multiple values.
It's good you're doing rigorous input testing in choose_number. However it has 2 while
True loops for no reason. Just having one does exactly the same job. Also you don't
need to call continue in either of the places you've used it. In both cases one iteration is
about to end and it will start a new iteration even if you remove those lines so they make
no difference.
9 in here is what's known as a 'magic number', that's a value that's used without making
it clear why. Instead of 9, you should use len(board) so that it's obvious why it matters. If
you don't want to call len each time, then set it as a value when you initialise board. Also
testing for a in range(0, len(board)) is a bit silly, instead use 2 less than operators.
Python allows you to compare three values at once, so you can do this:
if -1 < a < len(board):
You could do 0 <= if you prefer, but I like using the same operator on both sides.
Also a isn't a great name, consider using value or choice.
That's a lot of suggestions, so here's how I'd rewrite it:

def choose_number():
while True:
value = input()
try:
value = int(value) - 1
if -1 < value < len(board):
return value
else:
print("\nThat's not on the board. Try again")
except ValueError:
print("\nThat's not a number. Try again")
In check_board you're using for a in range(9) and then accessing board[a], but you
could instead use for cell in board, where cell (or whatever you choose to name it) is
now directly assigned to the value of each element of board. This is faster, easier and
more idiomatic.
for cell in board:
if cell in "XO":
count += 1
You can also use all for this looped test. all will basically run a test on all elements of
an iterator and return True if they all turn out to be True. Which is basically what you're
doing with your count value. What you need to do is pass a generator expression to all.
Generator expressions are like for loops but collapsed into a single expression. Here's
how yours might look:
if all(cell in "XO" for cell in board):
print("The game ends in a Tie\n")
return True
Instead of storing end then immediately using it once, just use the returned value
from check_board directly. Also don't use == True. Just test if value, it's more idiomatic.
If you want to explicitly test that it's a boolean then use is True instead.
if check_board():
break
Sample Run of Tic Tac Toe
Welcome to Tic Tac Toe!
Do you want to be X or O?
X
The computer will go first.
| |
O| |
| |
-----------
| |
| |
| |
-----------
| |
| |
| |
What is your next move? (1-9)
3
| |
O| |
| |
-----------
| |
| |
| |
-----------
| |
O| |X
| |
What is your next move? (1-9)
4
| |
O| |O
| |
-----------
| |
X| |
| |
-----------
| |
O| |X
| |
What is your next move? (1-9)
5
| |
O|O|O
| |
-----------
| |
X|X|
| |
-----------
| |
O| |X
| |
The computer has beaten you! You lose.
Do you want to play again? (yes or no)
no
Source Code of Tic Tac Toe
In a new file editor window, type in the following source code and save it as tictactoe.py. Then run the
game by pressing F5.
tictactoe.py
1. # Tic Tac Toe
2.
3. import random
4.
5. def drawBoard(board):
6. # This function prints out the board that it was passed.
7.
8. # "board" is a list of 10 strings representing the board (ignore index 0)
9. print(' | |')
10. print(' ' + board[7] + ' | ' + board[8] + ' | ' + board[9])
11. print(' | |')
12. print('-----------')
13. print(' | |')
14. print(' ' + board[4] + ' | ' + board[5] + ' | ' + board[6])
15. print(' | |')
16. print('-----------')
17. print(' | |')
18. print(' ' + board[1] + ' | ' + board[2] + ' | ' + board[3])
19. print(' | |')
20.
21. def inputPlayerLetter():
22. # Lets the player type which letter they want to be.
23. # Returns a list with the player’s letter as the first item, and the computer's letter as the
second.
24. letter = ''
25. while not (letter == 'X' or letter == 'O'):
26. print('Do you want to be X or O?')
27. letter = input().upper()
28.
29. # the first element in the list is the player’s letter, the second is the computer's letter.
30. if letter == 'X':
31. return ['X', 'O']
32. else:
33. return ['O', 'X']
34.
35. def whoGoesFirst():
36. # Randomly choose the player who goes first.
37. if random.randint(0, 1) == 0:
38. return 'computer'
39. else:
40. return 'player'
41.
42. def playAgain():
43. # This function returns True if the player wants to play again, otherwise it returns False.
44. print('Do you want to play again? (yes or no)')
45. return input().lower().startswith('y')
46.
47. def makeMove(board, letter, move):
48. board[move] = letter
49.
50. def isWinner(bo, le):
51. # Given a board and a player’s letter, this function returns True if that player has won.
52. # We use bo instead of board and le instead of letter so we don’t have to type as much.
53. return ((bo[7] == le and bo[8] == le and bo[9] == le) or # across the top
54. (bo[4] == le and bo[5] == le and bo[6] == le) or # across the middle
55. (bo[1] == le and bo[2] == le and bo[3] == le) or # across the bottom
56. (bo[7] == le and bo[4] == le and bo[1] == le) or # down the left side
57. (bo[8] == le and bo[5] == le and bo[2] == le) or # down the middle
58. (bo[9] == le and bo[6] == le and bo[3] == le) or # down the right side
59. (bo[7] == le and bo[5] == le and bo[3] == le) or # diagonal
60. (bo[9] == le and bo[5] == le and bo[1] == le)) # diagonal
61.
62. def getBoardCopy(board):
63. # Make a duplicate of the board list and return it the duplicate.
64. dupeBoard = []
65.
66. for i in board:
67. dupeBoard.append(i)
68.
69. return dupeBoard
70.
71. def isSpaceFree(board, move):
72. # Return true if the passed move is free on the passed board.
73. return board[move] == ' '
74.
75. def getPlayerMove(board):
76. # Let the player type in their move.
77. move = ' '
78. while move not in '1 2 3 4 5 6 7 8 9'.split() or not isSpaceFree(board, int(move)):
79. print('What is your next move? (1-9)')
80. move = input()
81. return int(move)
82.
83. def chooseRandomMoveFromList(board, movesList):
84. # Returns a valid move from the passed list on the passed board.
85. # Returns None if there is no valid move.
86. possibleMoves = []
87. for i in movesList:
88. if isSpaceFree(board, i):
89. possibleMoves.append(i)
90.
91. if len(possibleMoves) != 0:
92. return random.choice(possibleMoves)
93. else:
94. return None
95.
96. def getComputerMove(board, computerLetter):
97. # Given a board and the computer's letter, determine where to move and return that move.
98. if computerLetter == 'X':
99. playerLetter = 'O'
100. else:
101. playerLetter = 'X'
102.
103. # Here is our algorithm for our Tic Tac Toe AI:
104. # First, check if we can win in the next move
105. for i in range(1, 10):
106. copy = getBoardCopy(board)
107. if isSpaceFree(copy, i):
108. makeMove(copy, computerLetter, i)
109. if isWinner(copy, computerLetter):
110. return i
111.
112. # Check if the player could win on their next move, and block them.
113. for i in range(1, 10):
114. copy = getBoardCopy(board)
115. if isSpaceFree(copy, i):
116. makeMove(copy, playerLetter, i)
117. if isWinner(copy, playerLetter):
118. return i
119.
120. # Try to take one of the corners, if they are free.
121. move = chooseRandomMoveFromList(board, [1, 3, 7, 9])
122. if move != None:
123. return move
124.
125. # Try to take the center, if it is free.
126. if isSpaceFree(board, 5):
127. return 5
128.
129. # Move on one of the sides.
130. return chooseRandomMoveFromList(board, [2, 4, 6, 8])
131.
132. def isBoardFull(board):
133. # Return True if every space on the board has been taken. Otherwise return False.
134. for i in range(1, 10):
135. if isSpaceFree(board, i):
136. return False
137. return True
138.
139.
140. print('Welcome to Tic Tac Toe!')
141.
142. while True:
143. # Reset the board
144. theBoard = [' '] * 10
145. playerLetter, computerLetter = inputPlayerLetter()
146. turn = whoGoesFirst()
147. print('The ' + turn + ' will go first.')
148. gameIsPlaying = True
149.
150. while gameIsPlaying:
151. if turn == 'player':
152. # Player’s turn.
153. drawBoard(theBoard)
154. move = getPlayerMove(theBoard)
155. makeMove(theBoard, playerLetter, move)
156.
157. if isWinner(theBoard, playerLetter):
158. drawBoard(theBoard)
159. print('Hooray! You have won the game!')
160. gameIsPlaying = False
161. else:
162. if isBoardFull(theBoard):
163. drawBoard(theBoard)
164. print('The game is a tie!')
165. break
166. else:
167. turn = 'computer'
168.
169. else:
170. # Computer’s turn.
171. move = getComputerMove(theBoard, computerLetter)
172. makeMove(theBoard, computerLetter, move)
173.
174. if isWinner(theBoard, computerLetter):
175. drawBoard(theBoard)
176. print('The computer has beaten you! You lose.')
177. gameIsPlaying = False
178. else:
179. if isBoardFull(theBoard):
180. drawBoard(theBoard)
181. print('The game is a tie!')
182. break
183. else:
184. turn = 'player'
185.
186. if not playAgain():
187. break
Designing the Program
Figure 10-1 is what a flow chart of Tic Tac Toe could look like. In the Tic Tac Toe computer program
the player chooses if they want to be X or O. Who takes the first turn is randomly chosen. Then the
player and computer take turns making moves.
The boxes on the left side of the flow chart are what happens during the player’s turn. The right side
shows what happens on the computer's turn. After the player or computer makes a move, the program
checks if they won or caused a tie, and then the game switches turns. After the game is over, the
program asks the player if they want to play again.

Figure 10-1:flow chart for Tic Tac Toe

Figure 10-2:The board is numbered like the keyboard's number pad.

Representing the Board as Data


First, you must figure out how to represent the board as data in a variable. On paper, the Tic Tac Toe
board is drawn as a pair of horizontal lines and a pair of vertical lines, with either an X, O, or empty
space in each of the nine spaces.
In the program, the Tic Tac Toe board is represented as a list of strings. Each string will represent one
of the nine spaces on the board. To make it easier to remember which index in the list is for which
space, they will mirror the numbers on a keyboard’s number keypad, as shown in Figure 10-2.
The strings will either be 'X' for the X player, 'O' for the O player, or a single space ' ' for a blank
space.
So if a list with ten strings was stored in a variable named board, then board[7] would be the top-left
space on the board. board[5] would be the center. board[4] would be the left side space, and so on.
The program will ignore the string at index 0 in the list. The player will enter a number from 1 to 9 to
tell the game which space they want to move on.

Game AI
The AI needs to be able to look at a board and decide which types of spaces it will move on. To be
clear, we will label three types of spaces on the Tic Tac Toe board: corners, sides, and the center.
Figure 10-3 is a chart of what each space is.

Figure 10-3:Locations of the side, corner, and center places.

The AI’s smarts for playing Tic Tac Toe will follow a simple algorithm. An algorithm is a finite series
of instructions to compute a result. A single program can make use of several different algorithms. An
algorithm can be represented with a flow chart. The Tic Tac Toe AI’s algorithm will compute the best
move to make, as shown in Figure 10-4.
The AI’s algorithm will have the following steps:
1. First, see if there’s a move the computer can make that will win the game. If there is, take that
move. Otherwise, go to step 2.
2. See if there’s a move the player can make that will cause the computer to lose the game. If
there is, move there to block the player. Otherwise, go to step 3.
3. Check if any of the corner spaces (spaces 1, 3, 7, or 9) are free. If so, move there. If no corner
piece is free, then go to step 4.
4. Check if the center is free. If so, move there. If it isn’t, then go to step 5.
5. Move on any of the side pieces (spaces 2, 4, 6, or 8). There are no more steps, because if the
execution reaches step 5 the side spaces are the only spaces left.
This all takes place in the “Get computer's move.” box on the flow chart in Figure 10-1. You could
add this information to the flow chart with the boxes in Figure 10-4.

Figure-10-4:The five steps of the “Get computer's move” algorithm. The arrows leaving go to the
“Check if computer won” box.

This algorithm is implemented in the getComputerMove() function and the other functions
that getComputerMove() calls.

The Start of the Program


1. # Tic Tac Toe
2.
3. import random

The first couple of lines are a comment and importing the random module so you can call
the randint() function.

Printing the Board on the Screen


5. def drawBoard(board):
6. # This function prints out the board that it was passed.
7.
8. # "board" is a list of 10 strings representing the board (ignore index 0)
9. print(' | |')
10. print(' ' + board[7] + ' | ' + board[8] + ' | ' + board[9])
11. print(' | |')
12. print('-----------')
13. print(' | |')
14. print(' ' + board[4] + ' | ' + board[5] + ' | ' + board[6])
15. print(' | |')
16. print('-----------')
17. print(' | |')
18. print(' ' + board[1] + ' | ' + board[2] + ' | ' + board[3])
19. print(' | |')

The drawBoard() function will print the game board represented by the board parameter. Remember
that the board is represented as a list of ten strings, where the string at index 1 is the mark on space 1
on the Tic Tac Toe board, and so on. The string at index 0 is ignored. Many of the game’s functions
will work by passing a list of ten strings as the board.
Be sure to get the spacing right in the strings, otherwise the board will look funny when printed on the
screen. Here are some example calls (with an argument for board) to drawBoard() and what the
function would print:
>>> drawBoard([' ', ' ', ' ', ' ', 'X', 'O', ' ', 'X', ' ', 'O']
| |
X| |O
| |
-----------
| |
X|O|
| |
-----------
| |
| |
| |
>>> [' ', 'O', 'O', ' ', ' ', 'X', ' ', ' ', ' ', ' ']
| |
| |
| |
-----------
| |
|X|
| |
-----------
| |
O|O|
| |
>>> [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ']
| |
| |
| |
-----------
| |
| |
| |
-----------
| |
| |
| |

Letting the Player be X or O


21. def inputPlayerLetter():
22. # Lets the player type which letter they want to be.
23. # Returns a list with the player’s letter as the first item, and the computer's letter as the
second.
24. letter = ''
25. while not (letter == 'X' or letter == 'O'):
26. print('Do you want to be X or O?')
27. letter = input().upper()

The inputPlayerLetter() function asks if the player wants to be X or O. It will keep asking the player
until the player types in an X or O. Line 27 automatically changes the string returned by the call
to input() to uppercase letters with the upper() string method.
The while loop’s condition contains parentheses, which means the expression inside the parentheses is
evaluated first. If the letter variable was set to 'X', the expression would evaluate like this:
not (letter == 'X' or letter == 'O')

not ('X' == 'X' or 'X' == 'O')

not ( True or False)

not (True)

not True

False

If letter has the value 'X' or 'O', then the loop’s condition is False and lets the program execution
continue past the while-block.
29. # the first element in the list is the player’s letter, the second is the computer's letter.
30. if letter == 'X':
31. return ['X', 'O']
32. else:
33. return ['O', 'X']

This function returns a list with two items. The first item (the string at index 0) is the player’s letter,
and the second item (the string at index 1) is the computer's letter. These if-else statements chooses
the appropriate list to return.

Deciding Who Goes First


35. def whoGoesFirst():
36. # Randomly choose the player who goes first.
37. if random.randint(0, 1) == 0:
38. return 'computer'
39. else:
40. return 'player'

The whoGoesFirst() function does a virtual coin flip to determine whether the computer or the player
goes first. The coin flip is in calling random.randint(0, 1). If this function call returns a 0,
the whoGoesFirst() function returns the string 'computer'. Otherwise, the function returns the
string 'player'. The code that calls this function will use the return value to know who will make the
first move of the game.

Asking the Player to Play Again


42. def playAgain():
43. # This function returns True if the player wants to play again, otherwise it returns False.
44. print('Do you want to play again? (yes or no)')
45. return input().lower().startswith('y')

The playAgain() function asks the player if they want to play another game. The function
returns True if the player types in 'yes', 'YES', 'y', or anything that begins with the letter Y. For any
other response, the function returns False. This function is identical to the one in the Hangman game.

Placing a Mark on the Board


47. def makeMove(board, letter, move):
48. board[move] = letter

The makeMove() function is simple and only one line. The parameters are a list with ten strings
named board, one of the player’s letters (either 'X' or 'O') named letter, and a place on the board
where that player wants to go (which is an integer from 1 to 9) named move.
But wait a second. This code seems to change one of the items in the board list to the value in letter.
But because this code is in a function, the board parameter will be forgotten when the function
returns. Shouldn’t the change to board be forgotten as well?
Actually, this isn’t the case. This is because lists are special when you pass them as arguments to
functions. You are actually passing a reference of the list and not the list itself. Let’s learn about the
difference between lists and references to lists.

References
Try entering the following into the interactive shell:
>>> spam = 42
>>> cheese = spam
>>> spam = 100
>>> spam
100
>>> cheese
42

These results make sense from what you know so far. You assign 42 to the spam variable, and then
assign the value in spam and to the variable cheese. When you later overwrite spam to 100, this
doesn’t affect the value in cheese. This is because spam and cheese are different variables that store
different values.
But lists don’t work this way. When you assign a list to a variable with the = sign, you are actually
assigning a list reference to the variable. A reference is a value that points to some bit of data. Here is
some code that will make this easier to understand. Type this into the interactive shell:
>>> spam = [0, 1, 2, 3, 4, 5]
>>> cheese = spam
>>> cheese[1] = 'Hello!'
>>> spam
[0, 'Hello!', 2, 3, 4, 5]
>>> cheese
[0, 'Hello!', 2, 3, 4, 5]

This looks odd. The code only changed the cheese list, but it seems that both
the cheese and spam lists have changed. This is because the spam variable does not contain the list
value itself, but rather spam contains a reference to the list as shown in Figure 10-5. The actual list
itself is not contained in any variable, but rather exists outside of them.

Figure 10-5: Variables don’t store lists, but rather references to lists.

Notice that cheese = spam copies the list reference in spam to cheese, instead of copying the list
value itself. Now both spam and cheese store a reference that refers to the same list value. But there
is only one list. The list was not copied, the reference to the list was copied. Figure 10-6 shows this
copying.
Figure 10-6: Two variables store two references to the same list.

So the cheese[1] = 'Hello!' line changes the same list that spam refers to. This is why spam seems to
have the same list value that cheese does. They both have references that refer to the same list, as
shown in Figure 10-7.

Figure 10-7: Changing the list changes all variables with references to that list.

If you want spam and cheese to store two different lists, you have to create two different lists instead
of copying a reference:
>>> spam = [0, 1, 2, 3, 4, 5]
>>> cheese = [0, 1, 2, 3, 4, 5]

In the above example, spam and cheese have two different lists stored in them (even though these
lists are identical in content). Now if you modify one of the lists, it won’t affect the other
because spam and cheese have references to two different lists:
>>> spam = [0, 1, 2, 3, 4, 5]
>>> cheese = [0, 1, 2, 3, 4, 5]
>>> cheese[1] = 'Hello!'
>>> spam
[0, 1, 2, 3, 4, 5]
>>> cheese
[0, 'Hello!', 2, 3, 4, 5]

Figure 10-8 shows how the two references point to two different lists.

Figure 10-8: Two variables each storing references to two different lists.

Dictionaries also work the same way. Variables don’t store dictionaries, they store references to
dictionaries.

Using List References in makeMove()


Let’s go back to the makeMove() function:
47. def makeMove(board, letter, move):
48. board[move] = letter

When a list value is passed for the board parameter, the function's local variable is really a copy of the
reference to the list, not a copy of the list. But a copy of the reference still refers to the same list the
original reference refers. So any changes to board in this function will also happen to the original list.
Even though board is a local variable, the makeMove() function modifies the original list.
The letter and move parameters are copies of the string and integer values that you pass. Since they
are copies of values, if you modify letter or move in this function, the original variables you used
when you called makeMove() aren’t modified.

Checking if the Player Has Won


50. def isWinner(bo, le):
51. # Given a board and a player’s letter, this function returns True if that player has won.
52. # We use bo instead of board and le instead of letter so we don’t have to type as much.
53. return ((bo[7] == le and bo[8] == le and bo[9] == le) or # across the top
54. (bo[4] == le and bo[5] == le and bo[6] == le) or # across the middle
55. (bo[1] == le and bo[2] == le and bo[3] == le) or # across the bottom
56. (bo[7] == le and bo[4] == le and bo[1] == le) or # down the left side
57. (bo[8] == le and bo[5] == le and bo[2] == le) or # down the middle
58. (bo[9] == le and bo[6] == le and bo[3] == le) or # down the right side
59. (bo[7] == le and bo[5] == le and bo[3] == le) or # diagonal
60. (bo[9] == le and bo[5] == le and bo[1] == le)) # diagonal

Lines 53 to 60 in the isWinner() function are actually one long return statement. The bo and le names
are shortcuts for the board and letter parameters. These shorter names mean you have less to type in
this function. Remember, Python doesn’t care what you name your variables.
There are eight possible ways to win at Tic Tac Toe. You can have a line across the top, middle, and
bottom rows. Or you can have a line down the left, middle, or right columns. Or you can have a line
over either of the two diagonals.
Note that each line of the condition checks if the three spaces are equal to the letter provided
(combined with the and operator) and you use the or operator to combine the eight different ways to
win. This means only one of the eight ways must be true in order for us to say that the player who
owns letter in le is the winner.
Let’s pretend that le is 'O' and bo is [' ', 'O', 'O', 'O', ' ', 'X', ' ', 'X', ' ', ' ']. The board looks like this:
| |
X| |
| |
-----------
| |
|X|
| |
-----------
| |
O|O|O
| |

Here is how the expression after the return keyword on line 53 would evaluate:
53. return ((bo[7] == le and bo[8] == le and bo[9] == le) or # across the top
54. (bo[4] == le and bo[5] == le and bo[6] == le) or # across the middle
55. (bo[1] == le and bo[2] == le and bo[3] == le) or # across the bottom
56. (bo[7] == le and bo[4] == le and bo[1] == le) or # down the left side
57. (bo[8] == le and bo[5] == le and bo[2] == le) or # down the middle
58. (bo[9] == le and bo[6] == le and bo[3] == le) or # down the right side
59. (bo[7] == le and bo[5] == le and bo[3] == le) or # diagonal
60. (bo[9] == le and bo[5] == le and bo[1] == le)) # diagonal

First Python will replace the variables bo and le with the value inside of them:
return (('X' == 'O' and ' ' == 'O' and ' ' == 'O') or
(' ' == 'O' and 'X' == 'O' and ' ' == 'O') or
('O' == 'O' and 'O' == 'O' and 'O' == 'O') or
('X' == 'O' and ' ' == 'O' and 'O' == 'O') or
(' ' == 'O' and 'X' == 'O' and 'O' == 'O') or
(' ' == 'O' and ' ' == 'O' and 'O' == 'O') or
('X' == 'O' and 'X' == 'O' and 'O' == 'O') or
(' ' == 'O' and 'X' == 'O' and 'O' == 'O'))

Next, Python will evaluate all those == comparisons inside the parentheses to a Boolean value:
return ((False and False and False) or
(False and False and False) or
(True and True and True) or
(False and False and True) or
(False and False and True) or
(False and False and True) or
(False and False and True) or
(False and False and True))

Then the Python interpreter will evaluate all those expressions inside the parentheses:
return ((False) or
(False) or
(True) or
(False) or
(False) or
(False) or
(False) or
(False))

Since now there’s only one value inside the parentheses, you can get rid of them:
return (False or
False or
True or
False or
False or
False or
False or
False)

Now evaluate the expression that is connecter by all those or operators:


return (True)

Once again, get rid of the parentheses, and you are left with one value:
return True

So given those values for bo and le, the expression would evaluate to True. This is how the program
can tell if one of the players has won the game.

Duplicating the Board Data


62. def getBoardCopy(board):
63. # Make a duplicate of the board list and return it the duplicate.
64. dupeBoard = []
65.
66. for i in board:
67. dupeBoard.append(i)
68.
69. return dupeBoard

The getBoardCopy() function is here so that you can easily make a copy of a given 10-string list that
represents a Tic Tac Toe board in the game. There are times that you’ll want the AI algorithm to make
temporary modifications to a temporary copy of the board without changing the original board. In that
case, call this function to make a copy of the board's list. The new list is created on line 64, with the
blank list brackets [].
But the list stored in dupeBoard on line 64 is just an empty list. The for loop will iterate over
the board parameter, appending a copy of the string values in the original board to the duplicate
board. Finally, after the loop, dupeBoard is returned. The getBoardCopy() function builds up a copy
of the original board and returning a reference to this new board in dupeBoard, and not the original
one in board.

Checking if a Space on the Board is Free


71. def isSpaceFree(board, move):
72. # Return true if the passed move is free on the passed board.
73. return board[move] == ' '
This is a simple function that, given a Tic Tac Toe board and a possible move, will return if that move
is available or not. Remember that free spaces on the board lists are marked as a single space string. If
the item at the space’s index is not equal to, then the space is taken.

Letting the Player Enter Their Move


75. def getPlayerMove(board):
76. # Let the player type in their move.
77. move = ' '
78. while move not in '1 2 3 4 5 6 7 8 9'.split() or not isSpaceFree(board, int(move)):
79. print('What is your next move? (1-9)')
80. move = input()
81. return int(move)

The getPlayerMove() function asks the player to enter the number for the space they want to move on.
The loop makes sure the execution does not continue until the player has entered an integer from 1 to
9. It also checks that the space entered isn’t already taken, given the Tic Tac Toe board passed to the
function for the board parameter.
The two lines of code inside the while loop simply ask the player to enter a number from 1 to 9. The
condition on line 78 is True if either of the expressions on the left or right side of the or operator
is True.
The expression on the left side checks if the player’s move is equal to '1', '2', '3', and so on up
to '9' by creating a list with these strings (with the split() method) and checking if move is in this list.
'1 2 3 4 5 6 7 8 9'.split() evaluates to ['1', '2', '3', '4', '5', '6', '7', '8', '9'] , but the former easier to type.
The expression on the right side checks if the move that the player entered is a free space on the
board. It checks this by calling the isSpaceFree() function. Remember that isSpaceFree() will
return True if the move you pass is available on the board. Note that isSpaceFree() expects an integer
for move, so the int() function returns an integer form of move.
The not operators are added to both sides so that the condition is True when either of these
requirements are unfulfilled. This will cause the loop to ask the player again and again until they enter
a proper move.
Finally, line 81 returns the integer form of whatever move the player entered. Remember
that input() returns strings, so the int() function is called to return an integer form of the string.

Short-Circuit Evaluation
You may have noticed there’s a possible problem in the getPlayerMove() function. What if the player
typed in 'Z' or some other non-integer string? The expression move not in '1 2 3 4 5 6 7 8 9'.split() on
the left side of or would return False as expected, and then Python would evaluate the expression on
the right side of the or operator.
But calling int('Z') would cause an error. Python gives this error because the int() function can only
take strings of number characters, like '9' or '0', not strings like 'Z'.
As an example of this kind of error, try entering this into the interactive shell:
>>> int('42')
42
>>> int('Z')
Traceback (most recent call last):
File "<pyshell#3>", line 1, in <module>
int('Z')
ValueError: invalid literal for int() with base 10: 'Z'
But when you play the Tic Tac Toe game and try entering 'Z' for your move, this error doesn’t happen.
The reason is because the while loop’s condition is being short-circuited.
Short-circuiting means is that since the part on the left side of the or keyword (move not in '1 2 3 4 5
6 7 8 9'.split()) evaluates to True, the Python interpreter knows that the entire expression will evaluate
to True. It doesn’t matter if the expression on the right side of the or keyword evaluates
to True or False, because only one value on the side of the or operator needs to be True.
Think about it: The expression True or False evaluates to True and the expression True or True also
evaluates to True. If the value on the left side is True, it doesn’t matter what the value is on the right
side:
False and <<<anything>>> always evaluates to False
True or <<<anything>>> always evaluates to True
So Python stops checking the rest of the expression and doesn’t even bother evaluating the not
isSpaceFree(board, int(move)) part. This means the int() and the isSpaceFree() functions are never
called as long as move not in '1 2 3 4 5 6 7 8 9'.split() is True.
This works out well for the program, because if the right side is True then move isn’t a string in
number form. That would cause int() to give us an error. The only times move not in '1 2 3 4 5 6 7 8
9'.split()evaluates to False are when move isn’t a single-digit string. In that case, the call
to int() would not give us an error.

An Example of Short-Circuit Evaluation


Here’s a short program that gives a good example of short-circuiting. Try entering the following into
the interactive shell:
>>> def ReturnsTrue():
print('ReturnsTrue() was called.')
return True

>>> def ReturnsFalse():


print('ReturnsFalse() was called.')
return False

>>> ReturnsTrue()
ReturnsTrue() was called.
True
>>> ReturnsFalse()
ReturnsFalse() was called.
False

When ReturnsTrue() is called, it prints 'ReturnsTrue() was called.' and then also displays the return
value of ReturnsTrue(). The same goes for ReturnsFalse().
Now try entering the following into the interactive shell.
>>> ReturnsFalse() or ReturnsTrue()
ReturnsFalse() was called.
ReturnsTrue() was called.
True
>>> ReturnsTrue() or ReturnsFalse()
ReturnsTrue() was called.
True

The first part makes sense: The expression ReturnsFalse() or ReturnsTrue() calls both of the functions,
so you see both of the printed messages.
But the second expression only shows 'ReturnsTrue() was called.' but not 'ReturnsFalse() was called.'.
This is because Python did not call ReturnsFalse() at all. Since the left side of the or operator is True,
it doesn’t matter what ReturnsFalse() returns and Python doesn’t bother calling it. The evaluation was
short-circuited.
The same applies for the and operator. Try entering the following into the interactive shell:
>>> ReturnsTrue() and ReturnsTrue()
ReturnsTrue() was called.
ReturnsTrue() was called.
True
>>> ReturnsFalse() and ReturnsFalse()
ReturnsFalse() was called.
False

If the left side of the and operator is False, then the entire expression is False. It doesn’t matter
whether the right side of the and operator is True or False, so Python doesn’t bother evaluating it.
Both False and True and False and False evaluate to False, so Python short-circuits the evaluation.

Choosing a Move from a List of Moves


83. def chooseRandomMoveFromList(board, movesList):
84. # Returns a valid move from the passed list on the passed board.
85. # Returns None if there is no valid move.
86. possibleMoves = []
87. for i in movesList:
88. if isSpaceFree(board, i):
89. possibleMoves.append(i)

The chooseRandomMoveFromList() function is useful for the AI code later in the program.
The board parameter is a list of strings that represents a Tic Tac Toe board. The second
parameter movesList is a list of integers of possible spaces from which to choose. For example,
if movesList is [1, 3, 7, 9], that means chooseRandomMoveFromList() should return the integer for
one of the corner spaces.
However, chooseRandomMoveFromList() will first check that the space is valid to make a move on.
The possibleMoves list starts as a blank list. The for loop will iterate over movesList. The moves that
cause isSpaceFree() to return True are added to possibleMoves with the append() method.
91. if len(possibleMoves) != 0:
92. return random.choice(possibleMoves)
93. else:
94. return None

At this point, the possibleMoves list has all of the moves that were in movesList that are also free
spaces. If the list isn’t empty, then there’s at least one possible move that can be made on the board.
But this list could be empty. For example, if movesList was [1, 3, 7, 9] but the board represented by
the board parameter had all the corner spaces already taken, the possibleMoves list would be []. In
that case, len(possibleMoves) will evaluate to 0 and the function returns the value None. This next
section explains the None value.

The None Value


The None value is a value that represents the lack of a value. None is the only value of the data
type NoneType. It can be useful to use the None value when you need a value that means “does not
exist” or “none of the above”.
For example, say you had a variable named quizAnswer which holds the user’s answer to some True-
False pop quiz question. The variable could hold True or False for the user’s answer. You could
set quizAnswer to None if the user skipped the question and didn’t answer it. Using None would be
better because otherwise it may look like the user answered the question when they didn't.
Functions that return by reaching the end of the function (and not from a return statement)
have None for a return value. The None value is written without quotes and with a capital “N” and
lowercase “one”.
As a side note, None will not be displayed in the interactive shell like other values will be:
>>> 2 + 2
4
>>> 'This is a string value.'
'This is a string value.'
>>> None
>>>

Functions that don’t seem to return anything actually return the None value. For
example, print() returns None:
>>> spam = print('Hello world!')
Hello world!
>>> spam == None
True

Creating the Computer’s Artificial Intelligence


96. def getComputerMove(board, computerLetter):
97. # Given a board and the computer's letter, determine where to move and return that move.
98. if computerLetter == 'X':
99. playerLetter = 'O'
100. else:
101. playerLetter = 'X'

The getComputerMove() function contains the AI’s code. The first argument is a Tic Tac Toe board
for the board parameter. The second argument is letter for the computer either 'X' or 'O' in
the computerLetter parameter. The first few lines simply assign the other letter to a variable
named playerLetter. This way the same code can be used whether the computer is X or O.
The function will returns an integer from 1 to 9 representing the computer’s move.
Remember how the Tic Tac Toe AI algorithm works:
 First, see if there’s a move the computer can make that will win the game. If there is, take that
move. Otherwise, go to the second step.
 Second, see if there’s a move the player can make that will cause the computer to lose the
game. If there is, the computer should move there to block the player. Otherwise, go to the
third step.
 Third, check if any of the corner spaces (spaces 1, 3, 7, or 9) are free. If no corner space is
free, then go to the fourth step.
 Fourth, check if the center is free. If so, move there. If it isn’t, then go to the fifth step.
 Fifth, move on any of the side pieces (spaces 2, 4, 6, or 8). There are no more steps, because
if the execution has reached this step then the side spaces are the only spaces left.

The Computer Checks if it Can Win in One Move


103. # Here is our algorithm for our Tic Tac Toe AI:
104. # First, check if we can win in the next move
105. for i in range(1, 10):
106. copy = getBoardCopy(board)
107. if isSpaceFree(copy, i):
108. makeMove(copy, computerLetter, i)
109. if isWinner(copy, computerLetter):
110. return i

More than anything, if the computer can win in the next move, the computer should make that
winning move immediately. The for loop that starts on line 105 iterates over every possible move
from 1 to 9. The code inside the loop will simulate what would happen if the computer made that
move.
The first line in the loop (line 106) makes a copy of the board list. This is so the simulated move
inside the loop doesn’t modify the real Tic Tac Toe board stored in the board variable.
The getBoardCopy() returns an identical but separate board list value.
Line 107 checks if the space is free and if so, simulates making the move on the copy of the board. If
this move results in the computer winning, the function returns that move’s integer.
If none of the spaces results in winning, the loop will finally end and the program execution continues
to line 113.

The Computer Checks if the Player Can Win in One Move


112. # Check if the player could win on their next move, and block them.
113. for i in range(1, 10):
114. copy = getBoardCopy(board)
115. if isSpaceFree(copy, i):
116. makeMove(copy, playerLetter, i)
117. if isWinner(copy, playerLetter):
118. return i

Next, the code will simulate the human player moving on each of the spaces. The code is similar to
the previous loop except the player’s letter is put on the board copy. If the isWinner() function shows
that the player would win with this move, then the computer will return that same move to block this
from happening.
If the human player cannot win in one more move, the for loop will eventually finish and execution
continues to line 121.

Checking the Corner, Center, and Side Spaces (in that Order)
120. # Try to take one of the corners, if they are free.
121. move = chooseRandomMoveFromList(board, [1, 3, 7, 9])
122. if move != None:
123. return move

The call to chooseRandomMoveFromList() with the list of [1, 3, 7, 9] will ensure that it returns the
integer for one of the corner spaces: 1, 3, 7, or 9. If all the corner spaces are taken,
the chooseRandomMoveFromList()function will return None and execution moves on to line 126.
125. # Try to take the center, if it is free.
126. if isSpaceFree(board, 5):
127. return 5

If none of the corners are available, line 127 moves on the center space if it is free. If the center space
isn’t free, the execution moves on to line 130.
129. # Move on one of the sides.
130. return chooseRandomMoveFromList(board, [2, 4, 6, 8])
This code also makes a call to chooseRandomMoveFromList(), except you pass it a list of the side
spaces ([2, 4, 6, 8]). This function won’t return None because the side spaces are the only spaces that
can possibly be left. This ends the getComputerMove() function and the AI algorithm.

Checking if the Board is Full


132. def isBoardFull(board):
133. # Return True if every space on the board has been taken. Otherwise return False.
134. for i in range(1, 10):
135. if isSpaceFree(board, i):
136. return False
137. return True

The last function is isBoardFull(). This function returns True if the 10-string list board argument it was
passed has an 'X' or 'O' in every index (except for index 0, which is ignored). If there’s at least one
space in board that is set to a single space ' ' then it will return False.
The for loop will let us check indexes 1 through 9 on the board list. As soon as it finds a free space on
the board (that is, when isSpaceFree(board, i) returns True) the isBoardFull() function will
return False.
If execution manages to go through every iteration of the loop, then none of the spaces are free. Line
137 will then execute return True.

The Start of the Game


140. print('Welcome to Tic Tac Toe!')

Line 140 is the first line that isn’t inside of a function, so it is the first line of code that executes when
you run this program. It greets the player.
142. while True:
143. # Reset the board
144. theBoard = [' '] * 10

Line 142’s while loop has True for the condition and will keep looping until the execution encounters
a break statement. Line 144 sets up the main Tic Tac Toe board in a variable named theBoard. It is a
10-string list, where each string is a single space ' '.
Rather than type out this full list, line 144 uses list replication. It is shorter to type [' '] * 10 then [' ', '
', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '].

Deciding the Player’s Mark and Who Goes First


145. playerLetter, computerLetter = inputPlayerLetter()

The inputPlayerLetter() function lets the player type in whether they want to be X or O. The function
returns a 2-string list, either ['X', 'O'] or ['O', 'X']. The multiple assignment trick will
set playerLetter to the first item in the returned list and computerLetter to the second.
146. turn = whoGoesFirst()
147. print('The ' + turn + ' will go first.')
148. gameIsPlaying = True

The whoGoesFirst() function randomly decides who goes first, and returns either the string 'player' or
the string 'computer' and line 147 tells the player who will go first. The gameIsPlaying variable keeps
track of whether the game is still being played or if someone has won or tied.

Running the Player’s Turn


150. while gameIsPlaying:

Line 150’s loop will keep going back and forth between the code for the player’s turn and the
computer's turn, as long as gameIsPlaying is set to True.
151. if turn == 'player':
152. # Player’s turn.
153. drawBoard(theBoard)
154. move = getPlayerMove(theBoard)
155. makeMove(theBoard, playerLetter, move)

The turn variable was originally set by the whoGoesFirst() call on line 146. It is set either
to 'player' or 'computer'. If turn equals 'computer', then line 151’s condition is False and execution
jumps to line 169.
Line 153 calls drawBoard() and passes the theBoard variable to print the Tic Tac Toe board on the
screen. Then the getPlayerMove() function lets the player type in their move (and also makes sure it is
a valid move). The makeMove() function adds the player’s X or O to theBoard.
157. if isWinner(theBoard, playerLetter):
158. drawBoard(theBoard)
159. print('Hooray! You have won the game!')
160. gameIsPlaying = False

Now that the player has made their move, the computer should check if they have won the game with
this move. If the isWinner() function returns True, the if-block’s code displays the winning board and
prints a message telling them they have won.
The gameIsPlaying variable is also set to False so that execution doesn’t continue on to the computer's
turn.
161. else:
162. if isBoardFull(theBoard):
163. drawBoard(theBoard)
164. print('The game is a tie!')
165. break

If the player didn’t win with their last move, maybe their move filled up the entire board and tied the
game. In this else-block, the isBoardFull() function returns True if there are no more moves to make. In
that case, the if-block starting at line 162 displays the tied board and tell the player a tie has occurred.
The execution breaks out of the while loop and jumps to line 186.
166. else:
167. turn = 'computer'

If the player hasn’t won or tied the game, then line 167 sets the turn variable to 'computer' so that it
will execute the code for the computer’s turn on the next iteration.

Running the Computer’s Turn


If the turn variable wasn’t 'player' for the condition on line 151, then it must be the computer's turn.
The code in this else-block is similar to the code for the player’s turn.
169. else:
170. # Computer’s turn.
171. move = getComputerMove(theBoard, computerLetter)
172. makeMove(theBoard, computerLetter, move)
174. if isWinner(theBoard, computerLetter):
175. drawBoard(theBoard)
176. print('The computer has beaten you! You lose.')
177. gameIsPlaying = False
178. else:
179. if isBoardFull(theBoard):
180. drawBoard(theBoard)
181. print('The game is a tie!')
182. break
183. else:
184. turn = 'player'

Lines 170 to 184 are almost identical to the code for the player’s turn on lines 152 to 167. The only
difference is this the code uses the computer’s letter and calls getComputerMove().
If the game isn’t won or tied, line 184 sets turn to the player’s turn. There are no more lines of code
inside the while loop, so execution would jump back to the while statement on line 150.
186. if not playAgain():
187. break

Lines 186 and 187 are located immediately after the while-block started by the while statement on line
150. gameIsPlaying is set to False when the game has ended, so at this point the game asks the player
if they want to play again.
If playAgain() returns False, then the if statement’s condition is True (because the not operator reverses
the Boolean value) and the break statement executes. That breaks the execution out of the while loop
that was started on line 142. But since there are no more lines of code after that while-block, the
program terminates.

Summary
Creating a program that can play a game comes down to carefully considering all the possible
situations the AI can be in and how it should respond in each of those situations. The Tic Tac Toe AI is
simple because there are not many possible moves in Tic Tac Toe compared to a game like chess or
checkers.
Our AI checks if any possible move can allow itself to win. Otherwise, it checks if it must block the
player’s move. Then the AI simply chooses any available corner space, then the center space, then the
side spaces. This is a simple algorithm for the computer to follow.
The key to implementing our AI is by making copies of the board data and simulating moves on the
copy. That way, the AI code can see if a move results in a win or loss. Then the AI can make that move
on the real board. This type of simulation is effective at predicting what is a good move or not.

Potrebbero piacerti anche