using System; using System.Web; using System.Collections; using System.Web.Services; using System.Web.Services.Protocols; using System.ComponentModel; using System.Data; using System.Diagnostics; namespace ttt { /// /// Provides methods for playing the tic-tac-toe boardgame /// /// [WebService(Namespace = "http://harbormist.com/", Description = "A web service which provides a TicTacToe game. " + "[Programmers: Charlie Chambers, Jay Patel.]")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] public class TicTacToe : System.Web.Services.WebService { private ArrayList triplets = new ArrayList(); public const char USER_PIECE = 'X'; public const char COMP_PIECE = 'O'; public const char EMPT_PIECE = '_'; static public int NUM_CELLS = 9; public TicTacToe() { InitializeComponent(); triplets = new ArrayList(); triplets.Add(new Triplet(0, 1, 2)); triplets.Add(new Triplet(3, 4, 5)); triplets.Add(new Triplet(6, 7, 8)); triplets.Add(new Triplet(0, 3, 6)); triplets.Add(new Triplet(1, 4, 7)); triplets.Add(new Triplet(2, 5, 8)); triplets.Add(new Triplet(0, 4, 8)); triplets.Add(new Triplet(2, 4, 6)); } #region Component Designer generated code //Required by the Web Services Designer private IContainer components = null; /// /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// private void InitializeComponent() { } /// /// Clean up any resources being used. /// protected override void Dispose(bool disposing) { if (disposing && components != null) { components.Dispose(); } base.Dispose(disposing); } #endregion [WebMethod(Description = "Given a string of 9 characters representing the state of the board, each of which is one of: \n" + " TicTacToe.USER_PIECE, TicTacToe.COMP_PIECE, or TicTacToe.EMPT_PIECE," + " and an integer index from 0 to 8, representing the user move from the given board, " + " This returns a similar string with a new 'O' move in place" )] public string respondToUserMove(String boardState, int userMoveIndex) { //first put in user move, if allowed if (boardState[userMoveIndex] != EMPT_PIECE) return boardState; //can't move there, so return same board if (boardState.Length != NUM_CELLS) return "" + EMPT_PIECE + EMPT_PIECE + EMPT_PIECE + EMPT_PIECE + EMPT_PIECE + EMPT_PIECE + EMPT_PIECE + EMPT_PIECE + EMPT_PIECE; if (userMoveIndex >= NUM_CELLS || userMoveIndex < 0) return boardState; //don't let the user move if the game is won or lost foreach (Triplet t in triplets) { if (t.isWon(boardState) || t.isLost(boardState)) return boardState; } // user move is legal, so add it String afterUser = boardState.Substring(0, userMoveIndex); afterUser += USER_PIECE; if (afterUser.Length < NUM_CELLS) afterUser += boardState.Substring(userMoveIndex + 1); //has the user just won? if so, computer gets no move foreach (Triplet t in triplets) { if (t.isWon(afterUser)) return afterUser; } //are there no spaces for the computer to move? if (afterUser.IndexOf(EMPT_PIECE) == -1) return afterUser; //now to find the computer move... //first, two explicit conditions that we are fudging. if (afterUser.Equals( TicTacToe.USER_PIECE + TicTacToe.EMPT_PIECE + TicTacToe.EMPT_PIECE + TicTacToe.EMPT_PIECE + TicTacToe.COMP_PIECE + TicTacToe.EMPT_PIECE + TicTacToe.EMPT_PIECE + TicTacToe.EMPT_PIECE + TicTacToe.USER_PIECE )) { return ("" + TicTacToe.USER_PIECE + TicTacToe.COMP_PIECE + TicTacToe.EMPT_PIECE + TicTacToe.EMPT_PIECE + TicTacToe.COMP_PIECE + TicTacToe.EMPT_PIECE + TicTacToe.EMPT_PIECE + TicTacToe.EMPT_PIECE + TicTacToe.USER_PIECE ); } if (afterUser.Equals( TicTacToe.EMPT_PIECE + TicTacToe.EMPT_PIECE + TicTacToe.USER_PIECE + TicTacToe.EMPT_PIECE + TicTacToe.COMP_PIECE + TicTacToe.EMPT_PIECE + TicTacToe.USER_PIECE + TicTacToe.EMPT_PIECE + TicTacToe.EMPT_PIECE )) { return ("" + TicTacToe.EMPT_PIECE + TicTacToe.COMP_PIECE + TicTacToe.USER_PIECE + TicTacToe.EMPT_PIECE + TicTacToe.COMP_PIECE + TicTacToe.EMPT_PIECE + TicTacToe.USER_PIECE + TicTacToe.EMPT_PIECE + TicTacToe.EMPT_PIECE ); } int[] weights = new int[NUM_CELLS]; for (int i = 0; i < NUM_CELLS; i++) weights[i] = 0; //initialize weights to 0 expicitly foreach (Triplet t in triplets) { weights = t.addWeight(afterUser, weights); // add the influence of each triplet } //find the highest weight value that is a legal move int heighestWeight = -1; int bestMoveCell = 0; for (int i = 0; i < NUM_CELLS; i++) { if (weights[i] > heighestWeight && afterUser.Substring(i, 1) == ("" + EMPT_PIECE)) {//upgrade to better, empty-cell moves bestMoveCell = i; heighestWeight = weights[i]; } } String afterComputer = afterUser.Substring(0, bestMoveCell); afterComputer += COMP_PIECE; if (afterComputer.Length < NUM_CELLS) afterComputer += afterUser.Substring(bestMoveCell + 1); return afterComputer; } [WebMethod(Description = "Given a string of 9 characters representing the state of the board, " + " each of which is one of: \n" + " TicTacToe.USER_PIECE, TicTacToe.COMP_PIECE, or TicTacToe.EMPT_PIECE," + " This returns a status line (e.g. 'You lose', or 'You win') to explain " + " the status of the game to the user." )] public string getStatus(String boardState) { foreach (Triplet t in triplets) //we will check every "way" of winning { if (t.isWon(boardState)) return "You win."; if (t.isLost(boardState)) return "You lose."; } if (boardState.IndexOf(EMPT_PIECE) == -1) return "Stalemate."; //no empty squares return "Your turn"; //barring everything else, we are waiting for the user } } }