Assignment 3: Simple Game-Playing
CSE 415: Introduction to Artificial Intelligence
The University of Washington, Seattle, Autumn 2011
The reading for this assignment is Chapter 5 (Search) of Introduction to Artificial Intelligence Using Python.
Due Friday, October 21 through Catalyst CollectIt at 2:00 PM.

You should turn in 2 files: (1) a file (YourUWNetID)TTT.py with your Tic-Tac-Toe playing agent described in Part I, and (2) a file (YourUWNetID)KinARowMoveGenerator.py that provides your solution to Part II.
 

PART I: Tic-Tac-Toe Player (30 points).
Create a program that can participate in a game of Tic-Tac-Toe. Your program should consist of a single file, with a name of the form [UWNetID]TTT.py, where [UWNetID] is your own UWNetID. For example, my file would have tanimotoTTT.py for its name.

Within this file, you should define a function tttAllMoves(state) that accepts a state, represented in the format described below, and returns a list of [move, newState] pairs, each of which represents one legal move from the given state and the state that results from making that move. The given state's data structure should not be changed by your code. The list returned by your function should contain the result of all legal moves, only legal moves, and it should not contain any duplicate states. The order in which the new states occur on the list does not matter.

Three other functions should also be defined in your file. A function called introduce() should return a string that "introduces" the player, giving its full name (you get to make that up), the name and UWNetID of its creator (you), and any words to describe its character.

A function called nickname() should return a short version of the playing agent's name (16 characters or fewer). This name will be used to identify the player's moves in game transcripts.

The most important function is makeMove(currentState, currentRemark, timeLimit=10000). This should return a triple of the form [move, newState, newRemark, stats]. The move is a triple describing the chosen move, and its format is described later. The newState is the result of making the move from the given currentState. The currentRemark argument is a string representing a remark from the opponent on its last move. The timeLimit can be ignored in this assignment, but it will become important in Assignment 4; it will represent the number of milliseconds available for computing and returning the move. The newRemark to be returned must be a string. For this assignment, it can simply be a constant statement, such as "Tommy the Tic-Tac-Toe Terror has made his move!" However, it should be consistent with the name and character of your agent as described by your introduce() function. The fourth component of the returned list is the stats item. For this assignment, the stats item should be a string that reports the number of states examined in the course of determining the move.

Representations of moves and states:
We will use the following shorthand notation for representing a move: (isXtoMove, row, column). Example: (True, 2, 1) means that the player puts an X in row 2, column 1. (Middle of the bottom row of the Tic-Tac-Toe board).
A state is represented in the form of a pair [board, isXtoMove]. A board is represented as a list of lists. The initial state is:

[[[0, 0, 0],
  [0, 0, 0],
  [0, 0, 0]], True]
Here 0=blank (vacant), 1='X', 2='O', and 3='-' (forbidden). You can ignore the case of a forbidden square in this part of the assignment.

Testing:
You should test your player in a game situation by downloading both a gameMaster program and an opponent agent. These are available here.

PART II: K-in-a-Row Move Generator (20 points).
The game of Tic-Tac-Toe is one instance of a wider class of games that we'll call "K-in-a-Row on an M-by-N Board with Forbidden Squares", or simply "K-in-a-Row" for short. In order to specify an instance of this game, one must give an initial state and an integer k. Important aspects of the initial state are the following. M is the number of rows on the board. N is the number of columns on the board. Any of the squares on the board may be "forbidden" which means that neither X nor O is allowed to play in them. The matter of which squares are forbidden is a property of the instance of the game, and that propery does not change as the game progresses. Handicaps may be given as part of the initial state, and they are represented by the presence of one or more Xs or Os or both, already placed at the beginning. The object of the game is to be the first player to make a line of Xs or Os. The line must be k squares long. It can be oriented horizontally, vertically, or diagonally (at a 45-degree angle). There can be no breaks in the line.

Create a function kInARowAllMoves(state) that returns a list of [move, state] pairs for this more general version of the K-in-a-Row game. Your function may assume that a global variable K has, as its value, the integer that tells how many Xs or Os a player must have in a line to win.
The following is an example board in a KinARow game called "5 in a Row on 7-by-7 board with Corners Forbidden" is shown below.

[[3, 0, 0, 0, 0, 0, 3],
 [1, 1, 0, 0, 0, 0, 0], 
 [0, 0, 0, 0, 0, 0, 0], 
 [0, 0, 0, 0, 0, 0, 0], 
 [0, 0, 0, 0, 0, 2, 0], 
 [0, 0, 0, 0, 0, 0, 0], 
 [3, 0, 0, 0, 0, 0, 3]]
Here 0=blank (vacant), 1='X', 2='O', and 3='-' (forbidden).
Updates and Corrections If necessary, updates and corrections will be posted here and mentioned in class or on the mailing list. This page was last updated Oct. 13, 2011.