1# TicTacToe Factory - Example for illustrative purposes only.
2
3import smartpy as sp
4
5
6@sp.module
7def main():
8 class TicTacToe(sp.Contract):
9 def __init__(self, admin):
10 self.data.admin = admin
11 self.data.paused = False
12 self.data.boards = sp.big_map()
13 self.data.metaData = {}
14
15 @sp.entrypoint
16 def build(self, params):
17 sp.cast(params.game, sp.string)
18 assert not self.data.paused or sp.sender == self.data.admin
19 assert not self.data.boards.contains(params.game)
20 self.data.boards[params.game] = sp.record(
21 player1=params.player1,
22 player2=params.player2,
23 nbMoves=0,
24 winner=0,
25 draw=False,
26 deck={
27 0: {0: 0, 1: 0, 2: 0},
28 1: {0: 0, 1: 0, 2: 0},
29 2: {0: 0, 1: 0, 2: 0},
30 },
31 nextPlayer=1,
32 metaData={},
33 )
34
35 @sp.entrypoint
36 def deleteGame(self, params):
37 assert sp.sender == self.data.admin
38 del self.data.boards[params.game]
39
40 @sp.entrypoint
41 def setPause(self, params):
42 assert sp.sender == self.data.admin
43 self.data.paused = params
44
45 @sp.entrypoint
46 def setMetaData(self, params):
47 assert sp.sender == self.data.admin
48 sp.cast(params.name, sp.string)
49 sp.cast(params.value, sp.string)
50 self.data.metaData[params.name] = params.value
51
52 @sp.entrypoint
53 def setGameMetaData(self, params):
54 game = self.data.boards[params.game]
55 assert sp.sender == self.data.admin or sp.sender == game.player1
56 sp.cast(params.name, sp.string)
57 sp.cast(params.value, sp.string)
58 game.metaData[params.name] = params.value
59
60 @sp.entrypoint
61 def play(self, params):
62 assert not self.data.paused
63 game = self.data.boards[params.game]
64 assert game.winner == 0 and not game.draw
65 assert params.i >= 0 and params.i < 3
66 assert params.j >= 0 and params.j < 3
67 assert params.move == game.nextPlayer
68 assert game.deck[params.i][params.j] == 0
69 if params.move == 1:
70 assert sp.sender == game.player1
71 else:
72 assert sp.sender == game.player2
73 game.nextPlayer = 3 - game.nextPlayer
74 game.deck[params.i][params.j] = params.move
75 game.nbMoves += 1
76 game.winner = self.checkLine(
77 sp.record(winner=game.winner, line=game.deck[params.i])
78 )
79 game.winner = self.checkLine(
80 sp.record(
81 winner=game.winner,
82 line={
83 0: game.deck[0][params.j],
84 1: game.deck[1][params.j],
85 2: game.deck[2][params.j],
86 },
87 )
88 )
89 game.winner = self.checkLine(
90 sp.record(
91 winner=game.winner,
92 line={0: game.deck[0][0], 1: game.deck[1][1], 2: game.deck[2][2]},
93 )
94 )
95 game.winner = self.checkLine(
96 sp.record(
97 winner=game.winner,
98 line={0: game.deck[0][2], 1: game.deck[1][1], 2: game.deck[2][0]},
99 )
100 )
101 if game.nbMoves == 9 and game.winner == 0:
102 game.draw = True
103 self.data.boards[params.game] = game
104
105 @sp.private()
106 def checkLine(self, winner, line):
107 winner_ = winner
108 if line[0] != 0 and line[0] == line[1] and line[0] == line[2]:
109 winner_ = line[0]
110 return winner_
111
112
113# Tests
114if "main" in __name__:
115
116 @sp.add_test()
117 def test():
118 # define a contract
119 admin = sp.test_account("Admin")
120 alice = sp.test_account("Alice")
121 bob = sp.test_account("Robert")
122
123 scenario = sp.test_scenario("TicTacToeFactory", main)
124 c1 = main.TicTacToe(admin.address)
125
126 scenario.h1("Tic-Tac-Toe Games")
127 # show its representation
128 scenario.h2("A sequence of interactions with a winner")
129 scenario += c1
130 scenario.h2("Message execution")
131 scenario.h3("Building a contract")
132
133 g1 = "game 1"
134 c1.build(game=g1, player1=alice.address, player2=bob.address)
135
136 scenario.h3("A first move in the center")
137 c1.play(game=g1, i=1, j=1, move=1, _sender=alice)
138
139 g2 = "game 2"
140 c1.build(game=g2, player1=alice.address, player2=bob.address)
141 c1.deleteGame(game=g2, _sender=admin)
142
143 c1.setMetaData(name="toto", value="titi", _sender=admin)
144
145 c1.setGameMetaData(game=g1, name="toto", value="titi", _sender=alice)
146 c1.setGameMetaData(game=g1, name="toto2", value="titi2", _sender=admin)