Skip to content

uz0/lab2-vdikan-near-deblockle

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

near-deblockle

Deblockle Game contract on NEAR blockchain.

Game Description

Rules

The players start on a 7x7 board each with a set of cubes and a special win position on the board designated with a Star symbol, near the other player’s edge. So, for Player 1 (Bottom) win position is at (4,2); for Player 2 (Top) it is (4,6).

The players take turns starting from bottom side Player 1. Each turn has 2 phases: “Roll” and optional “Hop”.

During “Roll” phase the player rolls any of her cubes to the adjacent square across the cube edge, so that an upper face changes. Note that rolling a cube with “Star” facing up after the roll is only allowed into that player winning position! In that case the cube is removed from the board, and the other player takes turn (also in a “Roll” phase).

In other case, after the “Roll” phase the same player makes a “Hop”. During the “Hop”, the same cube that was rolled in the previous phase is shifted to another free square on a board, depending on its upper face after the “Roll”. During the “Hop” only the position of said cube is changed, the orientation of faces remains what it had become after “Roll”.

Cube faces and corresponding “Hop” shifts are:

Face titleFace number indexHop shift
“Star”1
“X-hop”2any closest unoccupied diagonal square
“sLide”3any one unoccupied square in the same row or column
“Hoops”4any one unoccupied square in the distance of 1 OR 3
“T-hop”5any closest unoccupied diagonal square in the same row or column
“stoP”6no hop phase; another player immediately takes turn

The goal of the game is to remove all one’s game cubes from the board.

This Implementation Details

Some peculiarities take place in the implementation of game rules for this contract. They may be changed in the future.

  • Players may pass their turn durin both “Roll” and “Hop” phases.
  • Though one cannot “roll” into her winning position not facing the “Star” up, she may “hop” there (effectively blocking the winning square for herself). Moving to the win position of the opponent Player (either “rolling” or “hopping”) is forbidden.
  • At the moment, the “sLide” and “Hoops” hop movements are strongly altered from what can be found in the original board game. It probably changes the balance a lot, and should be fixed.
  • The game cubes’ layout looks like the following (faces designated by capital letters from titles in the table):
      :-:  
      |L|  
    :-:-:-:
    |T|S|X|
    :-:-:-:
      |H|  
      :-:  
      |P|  
      :-:  
        

    Mind the “face number indexes” in the table. Each cube direction is encoded with indexes corresponding to “up”, “forward” and “right” faces. The opposite face indexes can be calculated at once as 7-complements to the given: the sum of the opposite face indexes is always 7 on a gaming d6 cube.

The standard 4x4 game setup looks like this:

Status: active, Player: 1, Phase: Roll

Game Board:
  :a  b  c  d  e  f  g
  :1  2  3  4  5  6  7  
1 |..|..|P2|..|X2|..|..|
2 |..|..|..|__|..|..|..|
3 |..|..|X2|..|T2|..|..|
4 |..|..|..|..|..|..|..|
5 |..|..|X1|..|X1|..|..|
6 |..|..|..|__|..|..|..|
7 |..|..|S1|..|L1|..|..|

Game cubes designated with capital letter from the column of face titles and a player index.

e.g. “P2” means game cube facing “stoP” up belonging to player 2, etc.

The sample endgame play can be found at the bottom of this page.

Deployment - Hackathon Edition

Alse, see a walkthrough of these steps inside ./test.sh in the repo.

  1. Run ./build.sh located in the project root. It compiles ./out/main.wasm.

(Alternatively, use pre-built in ./res/main.wasm)

near deploy --accountId $game_acc --wasmFile ./out/main.wasm 

An optional parameter num_cubes can be one of [1, 2, 3, 4] (defaults to 4). It is used to select one of standard game setups where each player starts with num_cubes game cubes.

near deploy --accountId $game_acc --initFunction new --initArgs '{"num_cubes": 3}'
  1. Connect roke.to streaming contract
near call $game_acc connect_streaming_contract \
    "{\"streaming_id\": \"$streaming_acc\"}" \
    --accountId $master_acc \
    --gas 300000000000000
  1. Then first player must deposit any amount of any token to the game contract account. Message should contain JSON map with key tokens_per_sec and a value as a string. Example with wNEAR FT:
near call wrap.testnet ft_transfer_call \
    "{\"receiver_id\": \"$game_acc\", \"amount\": \"300000000000000000000000\", \"msg\": \"{\"tokens_per_sec\": \"10000\"}\"}" \
    --depositYocto 1 \
    --gas 300000000000000 \
    --accountId $first_player_acc
  1. And the second player must do exactly the same: with the same token, with the same amount. Second player message unimportant, it won’t be used anywhere. Example with wNEAR FT:
near call wrap.testnet ft_transfer_call \
    "{\"receiver_id\": \"$game_acc\", \"amount\": \"300000000000000000000000\", \"msg\": \"\"}" \
    --depositYocto 1 \
    --gas 300000000000000 \
    --accountId $secod_player_acc
  1. Now you can start the game. It will start stream of tokens back to the second player’s account. The faster the first player will make it’s turn, the less tokens the second will recieve, and vice versa.
near call $game_acc start \
    --accountId $master_acc \
    --gas 300000000000000 

Contract View and Call Methods

View Methods

The game contract views designed to get the state of the game and individual game cubes.

game_state()

Return the overall state of the game. Log reflects position on the game board.

near view @dev-account game_state  --args '{"index": @index}' --accountId @account.testnet
Log [deblockle-v1.hawthorne.testnet]: Game board:
Log [deblockle-v1.hawthorne.testnet]:   :a  b  c  d  e  f  g
  :1  2  3  4  5  6  7  
1 |..|..|T2|..|H2|..|..|
2 |..|..|..|__|..|..|..|
3 |..|..|..|P2|..|..|..|
4 |..|..|..|..|..|..|..|
5 |..|..|..|H1|..|..|..|
6 |..|..|..|__|..|..|..|
7 |..|..|X1|..|H1|..|..|
{
  game: {
    phase: 'Roll',
    active_player: 1,
    board: [
      {
        player: 1,
        position: { x: 3, y: 7 },
        direction: { up: 2, front: 3, right: 6 }
      },
      {
        player: 1,
        position: { x: 5, y: 7 },
        direction: { up: 4, front: 1, right: 2 }
      },
      {
        player: 1,
        position: { x: 4, y: 5 },
        direction: { up: 4, front: 1, right: 2 }
      },
      {
        player: 2,
        position: { x: 3, y: 1 },
        direction: { up: 5, front: 3, right: 1 }
      },
      {
        player: 2,
        position: { x: 5, y: 1 },
        direction: { up: 4, front: 1, right: 2 }
      },
      {
        player: 2,
        position: { x: 4, y: 3 },
        direction: { up: 6, front: 4, right: 2 }
      }
    ]
  },
  is_finished: false,
  first_player: 'first.testnet',
  second_player: 'second.testnet'
}

cube_state(x: i8, y: i8)

Return the state of the cube at position (x, y) (if any): its owner player index and the orientation given by face index numbers of its up, forward and right face.

(as said in the Rules section, the remaining faces can be pin-pointed by the 7-complement rule).

The log reflects ascii-representation of the layout. It should help a player to orient the cube. Note: for developers this is a complementary view method, because all the cubes in play are listed in response of game_state.

near call @dev-account cube_state --args '{"x": 3, "y": 1}' --accountId @account.testnet
Log [deblockle-v1.hawthorne.testnet]:   :-:  
  |L|  
:-:-:-:
|P|T|S|
:-:-:-:
  |H|  
  :-:  
  |X|  
  :-:  
{
  player: 2,
  position: { x: 3, y: 1 },
  direction: { up: 5, front: 3, right: 1 }
}

Call Methods

The game contract calls are orders to perform the moves.

make_move(from_x: i8, from_y: i8, to_x: i8, to_y: i8)

For the game labeled with index this call attempts to move a cube, either “Roll” or “Hop” depending on the game’s phase, from square at position (from_x, from_y) to the square at (to_x, to_y).

The validity of a move is checked internally and if the move is valid, the game state is changed. In other case the state remains the same, and current player has to redo the move.

Note that the caller @account should be of course the ID of the games registered first_player or second_player, depending on who’s turn it is (active_player).

near call @dev-account make_move --args '{"from_x": 4, "from_y": 5, "to_x": 4, "to_y": 4}' --accountId @account.testnet
Doing account.functionCall()
	Log [deblockle-v1.hawthorne.testnet]: Player 1 Rolls to stop. Roll phase for another player 2.
	Log [deblockle-v1.hawthorne.testnet]:   :a  b  c  d  e  f  g
  :1  2  3  4  5  6  7  
1 |..|..|T2|..|H2|..|..|
2 |..|..|..|__|..|..|..|
3 |..|..|..|P2|..|..|..|
4 |..|..|..|P1|..|..|..|
5 |..|..|..|..|..|..|..|
6 |..|..|..|__|..|..|..|
7 |..|..|X1|..|H1|..|..|
{
  game: {
    phase: 'Roll',
    active_player: 2,
    board: [
      {
        player: 1,
        position: { x: 3, y: 7 },
        direction: { up: 2, front: 3, right: 6 }
      },
      {
        player: 1,
        position: { x: 5, y: 7 },
        direction: { up: 4, front: 1, right: 2 }
      },
      {
        player: 1,
        position: { x: 4, y: 4 },
        direction: { up: 6, front: 4, right: 2 }
      },
      {
        player: 2,
        position: { x: 3, y: 1 },
        direction: { up: 5, front: 3, right: 1 }
      },
      {
        player: 2,
        position: { x: 5, y: 1 },
        direction: { up: 4, front: 1, right: 2 }
      },
      {
        player: 2,
        position: { x: 4, y: 3 },
        direction: { up: 6, front: 4, right: 2 }
      }
    ]
  },
  is_finished: false,
  first_player: 'first.testnet',
  second_player: 'second.testnet'
}

pass_move()

Pass the rest of the move in the game, when called from proper @account (registered and active player in said game). The opponent player takes turn in a “Roll” phase.

Returns an updated game state.

near call @dev-account pass_move --accountId @account.testnet
Doing account.functionCall()
	Log [deblockle-v1.hawthorne.testnet]: Player 2 passed the turn. It is player 1 Roll phase.
{
  game: {
    phase: 'Roll',
    active_player: 1,
    board: [
      {
        player: 1,
        position: { x: 3, y: 7 },
        direction: { up: 2, front: 3, right: 6 }
      },
      {
        player: 1,
        position: { x: 5, y: 7 },
        direction: { up: 4, front: 1, right: 2 }
      },
      {
        player: 1,
        position: { x: 4, y: 4 },
        direction: { up: 6, front: 4, right: 2 }
      },
      {
        player: 2,
        position: { x: 3, y: 1 },
        direction: { up: 5, front: 3, right: 1 }
      },
      {
        player: 2,
        position: { x: 5, y: 1 },
        direction: { up: 4, front: 1, right: 2 }
      },
      {
        player: 2,
        position: { x: 4, y: 3 },
        direction: { up: 6, front: 4, right: 2 }
      }
    ]
  },
  is_finished: false,
  first_player: 'first.testnet',
  second_player: 'second.testnet'
}

reset(num_cubes: i8)

Completely resets game state. No refunds! (yet).

status() -> Status

Gets players information. If information is missing, some fields will be null.

Sample Endgame Play

Consider a situation, where it’s player 1 turn. “H1” is a 1st player’s cube facing “Hoops” up. Correspondingly, “L2” is a 2nd player’s cube facing “sLide” up.

  :a  b  c  d  e  f  g
  :1  2  3  4  5  6  7  
1 |..|..|..|..|..|..|..|
2 |..|..|..|__|..|..|..|
3 |..|..|..|..|..|..|..|
4 |..|..|..|H1|..|..|..|
5 |..|..|..|..|..|..|..|
6 |..|..|..|__|L2|..|..|
7 |..|..|..|..|..|..|..|

Player 1 Rolled from (4,4) to position (5,4):

  :a  b  c  d  e  f  g
  :1  2  3  4  5  6  7  
1 |..|..|..|..|..|..|..|
2 |..|..|..|__|..|..|..|
3 |..|..|..|..|..|..|..|
4 |..|..|..|..|X1|..|..|
5 |..|..|..|..|..|..|..|
6 |..|..|..|__|L2|..|..|
7 |..|..|..|..|..|..|..|

Next goes “Hop” phase of the same player 1. The player consults the current layout of her cube:

  :-:  
  |P|  
:-:-:-:
|L|X|H|
:-:-:-:
  |S|  
  :-:  
  |T|  
  :-:  

Hopping into (4,3) will win the game for her next turn.

Thus Player 1 Hopped from (5,4) to position (4,3).

  :a  b  c  d  e  f  g
  :1  2  3  4  5  6  7  
1 |..|..|..|..|..|..|..|
2 |..|..|..|__|..|..|..|
3 |..|..|..|X1|..|..|..|
4 |..|..|..|..|..|..|..|
5 |..|..|..|..|..|..|..|
6 |..|..|..|__|L2|..|..|
7 |..|..|..|..|..|..|..|

Next: Roll of the other player 2. She sees no opportunity to win this turn and rolls forward, to a stop:

  :a  b  c  d  e  f  g
  :1  2  3  4  5  6  7  
1 |..|..|..|..|..|..|..|
2 |..|..|..|__|..|..|..|
3 |..|..|..|X1|..|..|..|
4 |..|..|..|..|..|..|..|
5 |..|..|..|..|P2|..|..|
6 |..|..|..|__|..|..|..|
7 |..|..|..|..|..|..|..|

Player 1 takes the turn immediately after, rolls forward, scores and wins the game:

  :a  b  c  d  e  f  g
  :1  2  3  4  5  6  7  
1 |..|..|..|..|..|..|..|
2 |..|..|..|__|..|..|..|
3 |..|..|..|..|..|..|..|
4 |..|..|..|..|..|..|..|
5 |..|..|..|..|P2|..|..|
6 |..|..|..|__|..|..|..|
7 |..|..|..|..|..|..|..|

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published