github.com/muhammedhassanm/blockchain@v0.0.0-20200120143007-697261defd4d/sawtooth-core-master/sdk/examples/xo_javascript/xo_handler.js (about)

     1  /**
     2   * Copyright 2017-2018 Intel Corporation
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   * ------------------------------------------------------------------------------
    16   */
    17  
    18  'use strict'
    19  
    20  const XoPayload = require('./xo_payload')
    21  
    22  const { XO_NAMESPACE, XO_FAMILY, XoState } = require('./xo_state')
    23  
    24  const { TransactionHandler } = require('sawtooth-sdk/processor/handler')
    25  const { InvalidTransaction } = require('sawtooth-sdk/processor/exceptions')
    26  
    27  const _gameToStr = (board, state, player1, player2, name) => {
    28    board = board.replace(/-/g, ' ')
    29    board = board.split('')
    30    let out = ''
    31    out += `GAME: ${name}\n`
    32    out += `PLAYER 1: ${player1.substring(0, 6)}\n`
    33    out += `PLAYER 2: ${player2.substring(0, 6)}\n`
    34    out += `STATE: ${state}\n`
    35    out += `\n`
    36    out += `${board[0]} | ${board[1]} | ${board[2]} \n`
    37    out += `---|---|--- \n`
    38    out += `${board[3]} | ${board[4]} | ${board[5]} \n`
    39    out += `---|---|--- \n`
    40    out += `${board[6]} | ${board[7]} | ${board[8]} \n`
    41    return out
    42  }
    43  
    44  const _display = msg => {
    45    let n = msg.search('\n')
    46    let length = 0
    47  
    48    if (n !== -1) {
    49      msg = msg.split('\n')
    50      for (let i = 0; i < msg.length; i++) {
    51        if (msg[i].length > length) {
    52          length = msg[i].length
    53        }
    54      }
    55    } else {
    56      length = msg.length
    57      msg = [msg]
    58    }
    59  
    60    console.log('+' + '-'.repeat(length + 2) + '+')
    61    for (let i = 0; i < msg.length; i++) {
    62      let len = length - msg[i].length
    63  
    64      if (len % 2 === 1) {
    65        console.log(
    66          '+ ' +
    67            ' '.repeat(Math.floor(len / 2)) +
    68            msg[i] +
    69            ' '.repeat(Math.floor(len / 2 + 1)) +
    70            ' +'
    71        )
    72      } else {
    73        console.log(
    74          '+ ' +
    75            ' '.repeat(Math.floor(len / 2)) +
    76            msg[i] +
    77            ' '.repeat(Math.floor(len / 2)) +
    78            ' +'
    79        )
    80      }
    81    }
    82    console.log('+' + '-'.repeat(length + 2) + '+')
    83  }
    84  
    85  const _isWin = (board, letter) => {
    86    let wins = [
    87      [1, 2, 3],
    88      [4, 5, 6],
    89      [7, 8, 9],
    90      [1, 4, 7],
    91      [2, 5, 8],
    92      [3, 6, 9],
    93      [1, 5, 9],
    94      [3, 5, 7]
    95    ]
    96    let win
    97    for (let i = 0; i < wins.length; i++) {
    98      win = wins[i]
    99      if (board[win[0] - 1] === letter &&
   100          board[win[1] - 1] === letter &&
   101          board[win[2] - 1] === letter) {
   102        return true
   103      }
   104    }
   105    return false
   106  }
   107  
   108  class XOHandler extends TransactionHandler {
   109    constructor () {
   110      super(XO_FAMILY, ['1.0'], [XO_NAMESPACE])
   111    }
   112  
   113    apply (transactionProcessRequest, context) {
   114      let payload = XoPayload.fromBytes(transactionProcessRequest.payload)
   115      let xoState = new XoState(context)
   116      let header = transactionProcessRequest.header
   117      let player = header.signerPublicKey
   118  
   119      if (payload.action === 'create') {
   120        return xoState.getGame(payload.name)
   121          .then((game) => {
   122            if (game !== undefined) {
   123              throw new InvalidTransaction('Invalid Action: Game already exists.')
   124            }
   125  
   126            let createdGame = {
   127              name: payload.name,
   128              board: '---------',
   129              state: 'P1-NEXT',
   130              player1: '',
   131              player2: ''
   132            }
   133  
   134            _display(`Player ${player.toString().substring(0, 6)} created game ${payload.name}`)
   135  
   136            return xoState.setGame(payload.name, createdGame)
   137          })
   138      } else if (payload.action === 'take') {
   139        return xoState.getGame(payload.name)
   140          .then((game) => {
   141            try {
   142              parseInt(payload.space)
   143            } catch (err) {
   144              throw new InvalidTransaction('Space could not be converted as an integer.')
   145            }
   146  
   147            if (payload.space < 1 || payload.space > 9) {
   148              throw new InvalidTransaction('Invalid space ' + payload.space)
   149            }
   150  
   151            if (game === undefined) {
   152              throw new InvalidTransaction(
   153                'Invalid Action: Take requires an existing game.'
   154              )
   155            }
   156            if (['P1-WIN', 'P2-WIN', 'TIE'].includes(game.state)) {
   157              throw new InvalidTransaction('Invalid Action: Game has ended.')
   158            }
   159  
   160            if (game.player1 === '') {
   161              game.player1 = player
   162            } else if (game.player2 === '') {
   163              game.player2 = player
   164            }
   165            let boardList = game.board.split('')
   166  
   167            if (boardList[payload.space - 1] !== '-') {
   168              throw new InvalidTransaction('Invalid Action: Space already taken.')
   169            }
   170  
   171            if (game.state === 'P1-NEXT' && player === game.player1) {
   172              boardList[payload.space - 1] = 'X'
   173              game.state = 'P2-NEXT'
   174            } else if (
   175              game.state === 'P2-NEXT' &&
   176              player === game.player2
   177            ) {
   178              boardList[payload.space - 1] = 'O'
   179              game.state = 'P1-NEXT'
   180            } else {
   181              throw new InvalidTransaction(
   182                `Not this player's turn: ${player.toString().substring(0, 6)}`
   183              )
   184            }
   185  
   186            game.board = boardList.join('')
   187  
   188            if (_isWin(game.board, 'X')) {
   189              game.state = 'P1-WIN'
   190            } else if (_isWin(game.board, 'O')) {
   191              game.state = 'P2-WIN'
   192            } else if (game.board.search('-') === -1) {
   193              game.state = 'TIE'
   194            }
   195  
   196            let playerString = player.toString().substring(0, 6)
   197  
   198            _display(
   199              `Player ${playerString} takes space: ${payload.space}\n\n` +
   200                _gameToStr(
   201                  game.board,
   202                  game.state,
   203                  game.player1,
   204                  game.player2,
   205                  payload.name
   206                )
   207            )
   208  
   209            return xoState.setGame(payload.name, game)
   210          })
   211      } else if (payload.action === 'delete') {
   212        return xoState.getGame(payload.name)
   213          .then((game) => {
   214            if (game === undefined) {
   215              throw new InvalidTransaction(
   216                `No game exists with name ${payload.name}: unable to delete`)
   217            }
   218            return xoState.deleteGame(payload.name)
   219          })
   220      } else {
   221        throw new InvalidTransaction(
   222          `Action must be create, delete, or take not ${payload.action}`
   223        )
   224      }
   225    }
   226  }
   227  
   228  module.exports = XOHandler