Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

You are to write a lightweight web service in PHP for playing Connect Four games

ID: 3745123 • Letter: Y

Question

You are to write a lightweight web service in PHP for playing Connect Four games. The Connect Four game is a two-player connection game in which the players take turns dropping their discs from the top into a seven-column, six-row vertically suspended grid [Wikipedia]. The pieces fall straight down, occupying the next available space within the column. The objective of the game is to connect four of one's own discs next to each other vertically, horizontally, or diagonally before your opponent.

As a web service, your PHP code provides a few APIs implementing the logic, data or process for playing Connect Four games, not a complete Web application including a GUI. Do not include any GUI components in your web service. The web service APIs are predefined and specified as URLs (see below). Below are key requirements for your web service.

R1: The web service shall work with a provided Java client available and downloadble from the course website (c4Client.jar).

R2: The web service shall support multiple clients concurrently, each client playing against the server (see R5 below).

R3: A game board shall consist of six rows and seven columns, i.e., 6*7 places in which discs can be dropped.

R4: A column of the board shall be identified by a 0-based index, e.g., 2 for the third column.

R5: The web service shall provide at least two different move strategies for the computer, say Random and Smart. The Smart strategy shall be indeed "smart" to allow for a realistic play. Minimally, it should detect a winning/loosing row, i.e., three consecutive discs with an open end.

R6: The web service shall determine the outcome: win, loss, or draw.

The web service APIs are implemented as a set of URLs as specified below. All communications between the web service and a client shall be done using the HTTP query string and the JavaScript Object Notation (JSON), a lightweight data-interchange format (see www.json.org) [3]. All inputs to the web service shall be obtained from HTTP query strings, and all outputs to the client shall be written in JSON. Following the REST principles, the web service shall be stateless and provide the following three URLs:

1. http://<c4-home>/info (short for .../info/ or .../info/index.php), where <c4-home> is the address of your Connect Four service typically consisting of a host name and a pathname. Provide game information, including the board size and available computer move strategies. Below is a sample JSON output.

{"width":7,"height":6,"strategies":["Smart","Random"]}

Hint: Use json_encode() function to create a JSON (string) representation of a PHP value or object.

2. http://<c4-home>/new?strategy=s Create a new game to play against the specified computer strategy. A normal response will be a JSON string like:

{"response":true,"pid":"57cdc4815e1e5"}

where pid is a unique play identifier generated by the web service. It will be used to play the newly created game (see 3 below).

Upon an error, the web service will notify the client by providing an an appropriate error response like:

{"response": false, "reason": "Strategy not specified"}

{"response": false, "reason": "Unknown strategy"}

Hint: use uniqid() function to generate a unique identifier based on the current time in microseconds. Use the Strategy design pattern to define different strategy classes, e.g., RandomStrategy and SmartStrategy [Chapter 5 of 2].

3. http://<c4-home>/play?pid=p&move=x

Make a move by dropping a disc in the specified column, x, to play the specified game, p. Example: .../play/?pid=57cdc4815e1e5&move=3.

A normal response will be a JSON string like:

{"response": true,

"ack_move": {

"slot": 3,

"isWin": false, // winning move?

"isDraw": false, // draw?

"row": []}, // winning row if isWin is true

"move": {

"slot": 4,

"isWin": false,

"isDraw": false,

"row": []}}

where "ack_move" is the acknowledgement and the outcome of the requested move of the player, and "move" is the computer move made right after the player's; there will be no computer move if the player move is a game-ending (win or draw) move. For a winning move, the value of "row" is an array of numbers denoting the indices of the winning row [x1,y1,x2,y2,...,xn,yn], where x's and y's are 0-based column and row indices of places, e.g.,

"row":[0,5,1,5,2,5,3,5]

If there is an error, it should be reported to the client by providing an appropriate error message like:

{"response": false, "reason": "Pid not specified"}

{"response": false, "reason": "Move not specified"}

{"response": false, "reason": "Unknown pid"}

{"response": false, "reason": "Invalid slot, 10"}

Hint: Define several classes to model the Connect Four game, e.g., Play, Board, etc. The states of some of these classes need to be stored externally, say in a file, because the web service sessions are stateless and the game state should be preserved between sessions. You may use JSON string to persist game states.

Hint: You may use the player identifier (pid) as a file name to store the game state, and the game state may be stored as or restored from a JSON string; use json_encode() and json_decode() functions.

Hint: Use json_decode() function to convert a JSON encoded string to a PHP value or object.

With above three web service URLs, a Connect Four game can be played as follows:

Step 1: visit http://<c4-home>/info to find game info

Step 2: visit http://<c4-home>/new?strategy=s to create a new game

Step 3: repeatedly visit http://<c4-home>/play?pid=p&move=x to drop a disc, e.g. in pseudo code:

while (true) {

visit http://<c4-home>/play?pid=p&move=x

if (ack_move.isWin) {
break; // player won

} else if (ack_move.isDraw) {

break; // draw

} else if (move.isWin) {

break; // computer won

} else if (move.isDraw) {

break; // draw

}

}

HINTS

It is strongly recommended to use the PHP Development Tools (PDT), an Eclipse plugin for PHP (or PhpStorm for IntellJ IDEA).

Create in your src directory/folder three subdirectories/folders corresponding to the three URLs. Each subdirectory should have a PHP file named index.php, the entry point of the provided API, e.g.,

info/index.php

new/index.php

play/index.php

If this is your first PHP project, start early. You need a bit of time to get familiar with PHP scripting and to configure and get used to its support tools and development environment.

Explanation / Answer

<?php

class ConnectFour {

                protected $_rows = 6;

                protected $_columns = 6;

                protected $_board_array = array();

                protected $_current_player = 0;

                protected $_moves = 0;

                function __construct( $rows = 6, $cols = 6){

                                $this->_setDimensions( $rows, $cols );

                                $this->_initGame();

                }

               

               

                protected function _initializeGameBoard(){

                                //resets the board array

                                $_board_array = array();

                                for($i = 0; $i < $this->getRows() ; $i ++ ){

                                                $_board_array[$i] = array();

                                                for($j = 0; $j < $this->getColumns() ; $j ++ ){

                                                                //-1 means this slot is unoccupied.

                                                                $_board_array[$i][$j] = -1;

                                                }

                                }

                                $this->_setCurrentBoard($_board_array);

                }

               

                protected function _initGame(){

                                //Setup our game board

                                $this->_initializeGameBoard();

                                //Set a random player to start first

                                $this->_setCurrentPlayer(rand(1,2));

                               

                                //start dropping pieces

                                $this->_dropPiece();

                }

               

                protected function _dropPiece(){

                                //Check if total moves reached. (Recursive baseline)

                                if( $this->_moves >= ( $this->getRows() * $this->getColumns() )) {

                                                //No winner then =(

                                                $this->_showNoWinnerMessage();

                                                return false;

                                }

                               

                                //Random column chosen for placing chips

                                $_target_col = rand(0, $this->getColumns()-1);

                                $_current_board = $this->_getCurrentBoard();

                                for( $row = $this->getRows()-1; $row>=0; $row-- ){

                                                //If slot is currently empty

                                                if( $_current_board[$row][$_target_col] === -1 ){

                                                                //Set slot to current player

                                                                $_current_board[$row][$_target_col] = $this->_getCurrentPlayer();

                                                                //Update the no. of moves, might wana setter/getter this

                                                                $this->_moves++;

                                                                //Update the board

                                                                $this->_setCurrentBoard($_current_board);

                                                                //Print current board

                                                                $this->_printBoard();                                    

                //Check for winner

                                                                if( $this->_checkForWinner( $row, $_target_col ) ){

                                                                               

                                                                                //If winner is found

                                                                                $this->_showWinnerMessage();

                                                                               

                                                                                return false;                                                      

}

else{

                                                                               

                                                                                //Else continue the game

                                                                                //Change player

                                                                                $this->_togglePlayer();

                                                                                //Drop the piece

                                                                                $this->_dropPiece();

                                                                }

                                                               

                                                                //exit once a piece is dropped for this move

                                                                return false;

                                                }

                                }

                               

                                //If it comes to here, it means no slots are empty (column is full). Redo move again

                                $this->_dropPiece();

                               

                }

               

                protected function _printBoard(){

                               

                                print '<p>Player '. $this->_getCurrentPlayer() .': Move No. ' . $this->_moves . '</p>';

                                print '<table>';

                                $_board_array = $this->_getCurrentBoard();     

                                for($i = 0; $i < $this->getRows() ; $i ++ ){

                                                print '<tr>';

                                                for($j = 0; $j < $this->getColumns() ; $j ++ ){

                                                                //decoration

                                                                $_class = "";

                                                                if( $_board_array[$i][$j] === 1 ){

                                                                                //player 1 color

                                                                                $_class = "player-1";

                                                                }else if( $_board_array[$i][$j] === 2 ){

                                                                                //player 2 color

                                                                                $_class = "player-2";

                                                                }

                                                                print '<td class="'.$_class.'" >' . $_board_array[$i][$j] . '</td>';                  

                                                }

                                                print '</tr>';

                                }

                                print '</table>';

                }

                protected function _showWinnerMessage(){

                               

                                print '<p class="message">Player ' . $this->_getCurrentPlayer() .' wins the game!</p>';

                               

                }

               

               

                protected function _showNoWinnerMessage(){

                                print '<p class="message">No winner for this round.</p>';

                }

                protected function _togglePlayer(){

                               

                                $this->_setCurrentPlayer($this->_getCurrentPlayer()===1?2:1);

                }

               

                protected function _getCurrentPlayer(){

                                return $this->_current_player;                

                }

               

                protected function _setCurrentPlayer( $player_no ){

                                $this->_current_player = $player_no;   

                }

               

               

                protected function _getCurrentBoard(){

                                return $this->_board_array;      

                }

               

                protected function _setCurrentBoard( $board_array ){

                                $this->_board_array = $board_array;    

                }

               

               

                protected function _checkForWinner( $row, $col ){

                                if($this->_horizontalCheck($row, $col)

                                                                || $this->_verticalCheck($row, $col)

                                ){

                                                return true;

                                }

                                return false;

                }

               

               

                private function _horizontalCheck( $row, $col ){

                               

                                $_board_array = $this->_getCurrentBoard();

                                $_player = $_board_array[$row][$col];

                                $_count = 0;

                               

                                //count towards the left of current piece

                                for ( $i = $col; $i>=0; $i-- )

                                {

                                                if( $_board_array[$row][$i] !== $_player ){

                                                                break;

                                                }

                                                $_count++;

                                }

                               

                                //count towards the right of current piece

                                for ( $i = $col + 1; $i<$this->getColumns(); $i++ )

                                {             

                                                if( $_board_array[$row][$i] !== $_player ){

                                                                break;

                                                }

                                                               

                                                $_count++;        

                                }

                                return $_count>=4 ? true : false;

                }

               

               

                private function _verticalCheck( $row, $col ){

               

                                //if current piece is less than 4 pieces from bottom, skip check

                                if ( $row >= $this->getRows()-3 ) {

                                               

                                                return false;

                                }

                               

                                $_board_array = $this->_getCurrentBoard();

                                $_player = $_board_array[$row][$col];

                               

                                for ( $i = $row + 1; $i <= $row + 3; $i++ ){

                                                if($_board_array[$i][$col] !== $_player){

                                                                return false;      

                                                }

                                }

                               

                                return true;

                               

                }

               

                protected function _setDimensions($rows = 6, $cols = 6){

                                if(!isset($rows)) return;

                                $this->setRows($rows);

                                $this->setColumns($cols===null?$rows:$cols);

                }

               

               

                public function setRows($rows = 6){

                                $this->_rows = $rows;

               

                }

                public function getRows(){         

                                return $this->_rows;     

                }

               

                public function setColumns($col = 6){

                                $this->_columns = $col;

                }

               

               

                public function getColumns(){

                                return $this->_columns;

                }

}

?>

Hire Me For All Your Tutoring Needs
Integrity-first tutoring: clear explanations, guidance, and feedback.
Drop an Email at
drjack9650@gmail.com
Chat Now And Get Quote