@pompidup/kingdomino-engine 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/dist/index.d.ts +110 -0
  2. package/dist/index.js +1402 -2
  3. package/dist/index.js.map +1 -7
  4. package/package.json +6 -8
  5. package/dist/bin/test.d.ts +0 -1
  6. package/dist/index.cjs.js +0 -2
  7. package/dist/index.cjs.js.map +0 -7
  8. package/dist/src/_utils/container.d.ts +0 -9
  9. package/dist/src/application/engine/index.d.ts +0 -31
  10. package/dist/src/domain/engine/index.d.ts +0 -15
  11. package/dist/src/domain/entities/domino.d.ts +0 -22
  12. package/dist/src/domain/entities/game.d.ts +0 -38
  13. package/dist/src/domain/entities/kingdom.d.ts +0 -15
  14. package/dist/src/domain/port/dominoesRepository.d.ts +0 -4
  15. package/dist/src/domain/port/gamesRepository.d.ts +0 -6
  16. package/dist/src/domain/useCases/game/availableRules.d.ts +0 -4
  17. package/dist/src/domain/useCases/game/draw.d.ts +0 -6
  18. package/dist/src/domain/useCases/game/endGame.d.ts +0 -1
  19. package/dist/src/domain/useCases/game/endTurn.d.ts +0 -8
  20. package/dist/src/domain/useCases/game/firstTurn.d.ts +0 -8
  21. package/dist/src/domain/useCases/game/game.d.ts +0 -76
  22. package/dist/src/domain/useCases/game/init.d.ts +0 -4
  23. package/dist/src/domain/useCases/game/order.d.ts +0 -6
  24. package/dist/src/domain/useCases/game/pass.d.ts +0 -4
  25. package/dist/src/domain/useCases/game/pick.d.ts +0 -4
  26. package/dist/src/domain/useCases/game/place.d.ts +0 -4
  27. package/dist/src/domain/useCases/game/result.d.ts +0 -11
  28. package/dist/src/domain/useCases/game/scoring.d.ts +0 -8
  29. package/dist/src/domain/useCases/game/setRules.d.ts +0 -6
  30. package/dist/src/domain/useCases/game/setup.d.ts +0 -10
  31. package/dist/src/domain/useCases/game/startTurn.d.ts +0 -8
  32. package/dist/src/index.d.ts +0 -2
  33. package/dist/src/infrastructure/repositories/inMemoryDominoes.d.ts +0 -3
  34. package/dist/src/infrastructure/repositories/inMemoryGames.d.ts +0 -8
  35. package/dist/src/utils/container.d.ts +0 -9
  36. package/dist/src/utils/testHelpers.d.ts +0 -7
package/dist/index.js CHANGED
@@ -1,2 +1,1402 @@
1
- var A=[{left:{type:"wheat",crowns:0},right:{type:"wheat",crowns:0},number:1},{left:{type:"wheat",crowns:0},right:{type:"wheat",crowns:0},number:2},{left:{type:"forest",crowns:0},right:{type:"forest",crowns:0},number:3},{left:{type:"forest",crowns:0},right:{type:"forest",crowns:0},number:4},{left:{type:"forest",crowns:0},right:{type:"forest",crowns:0},number:5},{left:{type:"forest",crowns:0},right:{type:"forest",crowns:0},number:6},{left:{type:"water",crowns:0},right:{type:"water",crowns:0},number:7},{left:{type:"water",crowns:0},right:{type:"water",crowns:0},number:8},{left:{type:"water",crowns:0},right:{type:"water",crowns:0},number:9},{left:{type:"grass",crowns:0},right:{type:"grass",crowns:0},number:10},{left:{type:"grass",crowns:0},right:{type:"grass",crowns:0},number:11},{left:{type:"swamp",crowns:0},right:{type:"swamp",crowns:0},number:12},{left:{type:"wheat",crowns:0},right:{type:"forest",crowns:0},number:13},{left:{type:"wheat",crowns:0},right:{type:"water",crowns:0},number:14},{left:{type:"wheat",crowns:0},right:{type:"grass",crowns:0},number:15},{left:{type:"wheat",crowns:0},right:{type:"swamp",crowns:0},number:16},{left:{type:"forest",crowns:0},right:{type:"water",crowns:0},number:17},{left:{type:"forest",crowns:0},right:{type:"grass",crowns:0},number:18},{left:{type:"wheat",crowns:1},right:{type:"forest",crowns:0},number:19},{left:{type:"wheat",crowns:1},right:{type:"water",crowns:0},number:20},{left:{type:"wheat",crowns:1},right:{type:"grass",crowns:0},number:21},{left:{type:"wheat",crowns:1},right:{type:"swamp",crowns:0},number:22},{left:{type:"wheat",crowns:1},right:{type:"mine",crowns:0},number:23},{left:{type:"forest",crowns:1},right:{type:"wheat",crowns:0},number:24},{left:{type:"forest",crowns:1},right:{type:"wheat",crowns:0},number:25},{left:{type:"forest",crowns:1},right:{type:"wheat",crowns:0},number:26},{left:{type:"forest",crowns:1},right:{type:"wheat",crowns:0},number:27},{left:{type:"forest",crowns:1},right:{type:"water",crowns:0},number:28},{left:{type:"forest",crowns:1},right:{type:"grass",crowns:0},number:29},{left:{type:"water",crowns:1},right:{type:"wheat",crowns:0},number:30},{left:{type:"water",crowns:1},right:{type:"wheat",crowns:0},number:31},{left:{type:"water",crowns:1},right:{type:"forest",crowns:0},number:32},{left:{type:"water",crowns:1},right:{type:"forest",crowns:0},number:33},{left:{type:"water",crowns:1},right:{type:"forest",crowns:0},number:34},{left:{type:"water",crowns:1},right:{type:"forest",crowns:0},number:35},{left:{type:"wheat",crowns:0},right:{type:"grass",crowns:1},number:36},{left:{type:"water",crowns:0},right:{type:"grass",crowns:1},number:37},{left:{type:"wheat",crowns:0},right:{type:"swamp",crowns:1},number:38},{left:{type:"grass",crowns:0},right:{type:"swamp",crowns:0},number:39},{left:{type:"mine",crowns:1},right:{type:"wheat",crowns:0},number:40},{left:{type:"wheat",crowns:0},right:{type:"grass",crowns:2},number:41},{left:{type:"water",crowns:0},right:{type:"grass",crowns:2},number:42},{left:{type:"wheat",crowns:0},right:{type:"swamp",crowns:2},number:43},{left:{type:"grass",crowns:0},right:{type:"swamp",crowns:2},number:44},{left:{type:"mine",crowns:2},right:{type:"wheat",crowns:0},number:45},{left:{type:"swamp",crowns:0},right:{type:"mine",crowns:2},number:46},{left:{type:"swamp",crowns:0},right:{type:"mine",crowns:2},number:47},{left:{type:"wheat",crowns:0},right:{type:"mine",crowns:3},number:48}];var U=()=>{let e=[];return A.forEach(r=>{e.push({left:{type:r.left.type,crowns:r.left.crowns},right:{type:r.right.type,crowns:r.right.crowns},number:r.number})}),{getAll:()=>e}},v=U;var j=["Classic"];var M=e=>()=>{let r=e.dominoesRepository.getAll();return{id:e.uuidMethod(),dominoes:r,currentDominoes:[],players:[],kings:[],turn:0,maxTurns:0,maxDominoes:0,dominoesPerTurn:0,order:{}}};var z=()=>{let r={type:"empty",crowns:0};return Array.from({length:9},()=>Array.from({length:9},()=>r))},X=()=>{let e=z();return I(e,{x:4,y:4},{type:"castle",crowns:0})},I=(e,r,o)=>{let t=[...e[r.y]];return t[r.x]=o,[...e.slice(0,r.y),t,...e.slice(r.y+1)]},G=(e,r)=>{let o=e[r.y]?.[r.x];if(o===void 0)throw new Error("Invalid placement (not fit into the grid)");return o},ee=(e,r,o,t)=>{let n,s;return r==="horizontal"?o===0?(n={tile:t.left,position:{x:e.x,y:e.y}},s={tile:t.right,position:{x:e.x+1,y:e.y}}):(n={tile:t.right,position:{x:e.x,y:e.y}},s={tile:t.left,position:{x:e.x+1,y:e.y}}):o===0?(n={tile:t.left,position:{x:e.x,y:e.y}},s={tile:t.right,position:{x:e.x,y:e.y+1}}):(n={tile:t.right,position:{x:e.x,y:e.y}},s={tile:t.left,position:{x:e.x,y:e.y+1}}),[n,s]},te=(e,r,o,t,n)=>{let[s,a]=ee(r,o,t,n);if(!ne(e,s.position,a.position))throw new Error("Invalid placement (not free place)");if(!ie(e,[s,a]))throw new Error("Invalid placement (not fit into the grid)");let y=oe(e,s.position,a.position);if(y.length===0)throw new Error("Invalid placement (no adjacent)");if(!se(y,[s.tile,a.tile]))throw new Error("Invalid placement (no valid adjacent)");return re(e,[s,a])},re=(e,r)=>r.reduce((o,{tile:t,position:n})=>I(o,n,t),e),ne=(e,r,o)=>{let t=G(e,r),n=G(e,o);return!(t.type!=="empty"||n.type!=="empty")},oe=(e,r,o)=>{let t=r.x,n=r.y,s=o.x,a=o.y,y=[],i=[{x:t-1,y:n},{x:t,y:n-1},{x:t+1,y:n},{x:t,y:n+1},{x:s-1,y:a},{x:s,y:a-1},{x:s+1,y:a},{x:s,y:a+1}];return i.splice(i.findIndex(c=>c.x===t&&c.y===n),1),i.splice(i.findIndex(c=>c.x===s&&c.y===a),1),i.forEach(c=>{let m=G(e,c);m&&y.push(m)}),y},se=(e,r)=>e.some(o=>r.some(t=>t.type===o.type||o.type==="castle")),ie=(e,r)=>{let t=[...e];t[r[0].position.y][r[0].position.x]=r[0].tile,t[r[1].position.y][r[1].position.x]=r[1].tile;let n=t.map(m=>m.filter(u=>u.type!=="empty")),s=t[0].map((m,u)=>t.map(d=>d[u]).filter(d=>d?.type!=="empty")),a=n.map(m=>m.length),y=s.map(m=>m.length),i=Math.max(...a),c=Math.max(...y);return!(i>5||c>5)},ae={createEmptyKingdom:z,createKingdomWithCastle:X,getTile:G,placeDomino:te},S=ae;var C=e=>r=>{let{state:o,players:t}=r;if(!t)throw new Error("There must be at least 2 players");if(t.length>4)throw new Error("There must be no more than 4 players");if(t.length<2)throw new Error("There must be at least 2 players");let{dominoes:n}=o,{randomMethod:s,uuidMethod:a}=e,{maxDominoes:y,dominoesPerTurn:i,maxTurns:c}=O[t.length],m=s(n);m.splice(y);let u=t.map(w=>({...w,kingdom:S.createKingdomWithCastle(),id:a()})),d;u.length===2?d=[{id:a(),playerId:u[0].id,order:1,turnEnded:!1,hasPick:!1,hasPlace:!1},{id:a(),playerId:u[0].id,order:2,turnEnded:!1,hasPick:!1,hasPlace:!1},{id:a(),playerId:u[1].id,order:3,turnEnded:!1,hasPick:!1,hasPlace:!1},{id:a(),playerId:u[1].id,order:4,turnEnded:!1,hasPick:!1,hasPlace:!1}]:d=u.map((w,h)=>({id:a(),playerId:w.id,order:h+1,turnEnded:!1,hasPick:!1,hasPlace:!1}));let l=s(d);return l.forEach((w,h)=>{w.order=h+1}),l.sort((w,h)=>w.order-h.order),{...o,dominoes:m,players:u,kings:l,maxTurns:c,maxDominoes:y,dominoesPerTurn:i,turn:0}};var F=e=>{let{state:r}=e,o=r.turn+1,t=r.kings;return t.forEach(s=>{s.turnEnded=!1,s.hasPick=!1,s.hasPlace=!1}),{game:{...r,kings:t,turn:o}}};var V=e=>{let{kingId:r,data:o}=e,{state:t,dominoPick:n}=o,{currentDominoes:s,kings:a}=t;if(!L(t,r))throw new Error("It is not your turn");if(a.find(l=>l.id===r)?.hasPick)throw new Error("You have already picked");let i=N(t,n);if((l=>l.error!==void 0)(i))throw new Error(i.error);let m=s.map(l=>(l.domino.number===n&&(l.picked=!0,l.kingId=r),l)),u=a.map(l=>(l.id===r&&(l.hasPick=!0,l.turnEnded=!0,l.dominoPicked=i.domino),l));return{...t,currentDominoes:m,kings:u}};var H=e=>{let{kingId:r,data:o}=e,{state:t,position:n,orientation:s,rotation:a}=o,y=t.kings.find(d=>d.id===r),i=t.players.find(d=>d.id===y?.playerId),c=i?.kingdom;if(!c)throw new Error("Kingdom not found");let m=y?.dominoPicked;if(!m)throw new Error("Domino not found");return S.placeDomino(c,n,s,a,m),i.kingdom=c,y.hasPlace=!0,{...t,kings:t.kings.map(d=>d.id===r?y:d)}};var W=e=>{let{state:r}=e,{kings:o,currentDominoes:t}=r;if(!o.every(i=>i.turnEnded))throw new Error("Not all kings have played");let s=o.map(i=>({...i,order:t.find(c=>c.kingId===i.id)?.position||0})),a=s.reduce((i,c)=>({...i,[c.order]:c.id}),{});return{...r,kings:s,order:a}};var Z=e=>{let{state:r}=e,o=[...r.dominoes],t=o.splice(0,r.dominoesPerTurn);return t.sort((s,a)=>s.number-a.number),{...r,dominoes:o,currentDominoes:t.map((s,a)=>({domino:s,picked:!1,kingId:null,position:a+1}))}};var J=e=>{let r=e.map(i=>i.map(()=>!1)),o=[],t=[[-1,0],[1,0],[0,-1],[0,1]],n=(i,c,m,u)=>{if(i<0||c<0||i>=e[0].length||c>=e.length||r[c][i]||e[c][i].type!==m||e[c][i].type==="empty"||e[c][i].type==="castle")return;r[c][i]=!0;let d=o.find(l=>l.type===m&&l.tiles.some(([T,w])=>{for(let[h,K]of t)if(T+h===i&&w+K===c)return!0;return!1}));d?(d.crowns+=u,d.size++,d.tiles.push([i,c])):o.push({type:m,crowns:u,size:1,tiles:[[i,c]]}),t.forEach(([l,T])=>{let w=i+l,h=c+T;w>=0&&h>=0&&w<e[0].length&&h<e.length&&e[h][w].type===m&&n(w,h,e[h][w].type,e[h][w].crowns)})};if(e.forEach((i,c)=>{i.forEach((m,u)=>{r[c][u]||n(u,c,m.type,m.crowns)})}),o.length===0)return{score:0,maxPropertiesSize:0,totalCrowns:0};let s=o.reduce((i,c)=>i+c.crowns*c.size,0),a=Math.max(...o.map(i=>i.size??0)),y=o.reduce((i,c)=>i+c.crowns,0);return{score:s,maxPropertiesSize:a,totalCrowns:y}};var Y=e=>{let{kingId:r,data:o}=e,{state:t}=o,n=t.kings.find(a=>a.id===r);if(!n)throw new Error("King not found");return n.hasPlace=!0,{...t,kings:t.kings.map(a=>a.id===r?n:a)}};var ce=e=>({init:M(e),setup:C(e),startTurn:F,pick:V,place:H,pass:Y,definePlayerOrder:W,draw:Z,calculateScore:J}),L=(e,r)=>{let{kings:o,currentDominoes:t}=e,n=o.find(a=>a.id===r)?.order,s=t.filter(a=>a.picked);return n===s.length+1},N=(e,r)=>{let{currentDominoes:o}=e,t=o.find(n=>n.domino.number===r);return t?t.picked?{error:"Domino already picked"}:t:{error:"Domino not found"}},O={2:{kings:2,maxDominoes:24,dominoesPerTurn:4,maxTurns:6},3:{kings:1,maxDominoes:36,dominoesPerTurn:3,maxTurns:12},4:{kings:1,maxDominoes:48,dominoesPerTurn:4,maxTurns:12}},_=ce;var $=e=>{e.sort((t,n)=>t.details.score!==n.details.score?n.details.score-t.details.score:t.details.maxPropertiesSize!==n.details.maxPropertiesSize?n.details.maxPropertiesSize-t.details.maxPropertiesSize:n.details.totalCrowns-t.details.totalCrowns);let r=[],o=!1;r.push({...e[0],position:1});for(let t=1;t<e.length;t++){let n=e[t],s=e[t-1];s&&n&&n.details.score===s.details.score&&n.details.maxPropertiesSize===s.details.maxPropertiesSize&&n.details.totalCrowns===s.details.totalCrowns&&(o=!0),o?r.push({...n,position:r[t-1].position}):r.push({...n,position:t+1}),o=!1}return r};var pe=()=>{let e={dominoesRepository:v(),uuidMethod:()=>`uuid-${Math.random()}`,randomMethod:p=>p},{init:r,setup:o,startTurn:t,pick:n,place:s,pass:a,definePlayerOrder:y,draw:i,calculateScore:c}=_(e),m=()=>j,u=(p,f)=>f,d=p=>[],l=(p,f)=>f,T=(p,f)=>{let x=o({state:p,players:f}),g=i({state:x});return{nextKing:g.kings[0].id,nextAction:"pick",game:g}},w=(p,f)=>{let x=a({kingId:f,action:"pass",data:{state:p}});return E(x,"pass",f)},h=(p,f,x,g,b)=>{let k=s({kingId:f,action:"place",data:{state:p,position:x,orientation:g,rotation:b}});return E(k,"place",f)},K=(p,f,x)=>{let g=n({kingId:f,action:"pick",data:{state:p,dominoPick:x}});return E(g,"pick",f)},R=p=>{let f=y({state:p}),x=i({state:f}),g=t({state:x});if(g.game.turn>g.game.maxTurns)throw new Error("Game is over");return g.game},E=(p,f,x)=>{let{kings:g,turn:b}=p;if(b===0){let P=g.find(D=>!D.hasPick);if(!P){let D=R(p);return{nextKing:D.kings[0].id,nextAction:"place",game:D}}return{nextKing:P.id,nextAction:"pick",game:p}}if(f==="place"||f==="pass"){if(p.turn===p.maxTurns){let P=g.find(D=>!D.hasPlace);return P?{nextKing:P.id,nextAction:"place",game:p}:{nextKing:"none",nextAction:"end",game:p}}return{nextKing:x,nextAction:"pick",game:p}}if(g.every(P=>P.hasPick)){let P=R(p);return{nextKing:P.order[1],nextAction:"place",game:P}}return{nextKing:g.find(P=>!P.hasPlace).id,nextAction:"place",game:p}};return{init:r,getMode:m,setMode:u,getRules:d,setRules:l,start:T,pass:w,placeDomino:h,pickDomino:K,endGame:p=>{let f=p.players,x=[];for(let b of f){let k=c(b.kingdom);x.push({playerId:b.id,playerName:b.name,details:k})}return{result:$(x),game:p}}}},q=pe;var Ye=q;export{Ye as default};
2
- //# sourceMappingURL=index.js.map
1
+ // src/infrastructure/data/dominoes.json
2
+ var dominoes_default = [
3
+ {
4
+ left: {
5
+ type: "wheat",
6
+ crowns: 0
7
+ },
8
+ right: {
9
+ type: "wheat",
10
+ crowns: 0
11
+ },
12
+ number: 1
13
+ },
14
+ {
15
+ left: {
16
+ type: "wheat",
17
+ crowns: 0
18
+ },
19
+ right: {
20
+ type: "wheat",
21
+ crowns: 0
22
+ },
23
+ number: 2
24
+ },
25
+ {
26
+ left: {
27
+ type: "forest",
28
+ crowns: 0
29
+ },
30
+ right: {
31
+ type: "forest",
32
+ crowns: 0
33
+ },
34
+ number: 3
35
+ },
36
+ {
37
+ left: {
38
+ type: "forest",
39
+ crowns: 0
40
+ },
41
+ right: {
42
+ type: "forest",
43
+ crowns: 0
44
+ },
45
+ number: 4
46
+ },
47
+ {
48
+ left: {
49
+ type: "forest",
50
+ crowns: 0
51
+ },
52
+ right: {
53
+ type: "forest",
54
+ crowns: 0
55
+ },
56
+ number: 5
57
+ },
58
+ {
59
+ left: {
60
+ type: "forest",
61
+ crowns: 0
62
+ },
63
+ right: {
64
+ type: "forest",
65
+ crowns: 0
66
+ },
67
+ number: 6
68
+ },
69
+ {
70
+ left: {
71
+ type: "water",
72
+ crowns: 0
73
+ },
74
+ right: {
75
+ type: "water",
76
+ crowns: 0
77
+ },
78
+ number: 7
79
+ },
80
+ {
81
+ left: {
82
+ type: "water",
83
+ crowns: 0
84
+ },
85
+ right: {
86
+ type: "water",
87
+ crowns: 0
88
+ },
89
+ number: 8
90
+ },
91
+ {
92
+ left: {
93
+ type: "water",
94
+ crowns: 0
95
+ },
96
+ right: {
97
+ type: "water",
98
+ crowns: 0
99
+ },
100
+ number: 9
101
+ },
102
+ {
103
+ left: {
104
+ type: "grass",
105
+ crowns: 0
106
+ },
107
+ right: {
108
+ type: "grass",
109
+ crowns: 0
110
+ },
111
+ number: 10
112
+ },
113
+ {
114
+ left: {
115
+ type: "grass",
116
+ crowns: 0
117
+ },
118
+ right: {
119
+ type: "grass",
120
+ crowns: 0
121
+ },
122
+ number: 11
123
+ },
124
+ {
125
+ left: {
126
+ type: "swamp",
127
+ crowns: 0
128
+ },
129
+ right: {
130
+ type: "swamp",
131
+ crowns: 0
132
+ },
133
+ number: 12
134
+ },
135
+ {
136
+ left: {
137
+ type: "wheat",
138
+ crowns: 0
139
+ },
140
+ right: {
141
+ type: "forest",
142
+ crowns: 0
143
+ },
144
+ number: 13
145
+ },
146
+ {
147
+ left: {
148
+ type: "wheat",
149
+ crowns: 0
150
+ },
151
+ right: {
152
+ type: "water",
153
+ crowns: 0
154
+ },
155
+ number: 14
156
+ },
157
+ {
158
+ left: {
159
+ type: "wheat",
160
+ crowns: 0
161
+ },
162
+ right: {
163
+ type: "grass",
164
+ crowns: 0
165
+ },
166
+ number: 15
167
+ },
168
+ {
169
+ left: {
170
+ type: "wheat",
171
+ crowns: 0
172
+ },
173
+ right: {
174
+ type: "swamp",
175
+ crowns: 0
176
+ },
177
+ number: 16
178
+ },
179
+ {
180
+ left: {
181
+ type: "forest",
182
+ crowns: 0
183
+ },
184
+ right: {
185
+ type: "water",
186
+ crowns: 0
187
+ },
188
+ number: 17
189
+ },
190
+ {
191
+ left: {
192
+ type: "forest",
193
+ crowns: 0
194
+ },
195
+ right: {
196
+ type: "grass",
197
+ crowns: 0
198
+ },
199
+ number: 18
200
+ },
201
+ {
202
+ left: {
203
+ type: "wheat",
204
+ crowns: 1
205
+ },
206
+ right: {
207
+ type: "forest",
208
+ crowns: 0
209
+ },
210
+ number: 19
211
+ },
212
+ {
213
+ left: {
214
+ type: "wheat",
215
+ crowns: 1
216
+ },
217
+ right: {
218
+ type: "water",
219
+ crowns: 0
220
+ },
221
+ number: 20
222
+ },
223
+ {
224
+ left: {
225
+ type: "wheat",
226
+ crowns: 1
227
+ },
228
+ right: {
229
+ type: "grass",
230
+ crowns: 0
231
+ },
232
+ number: 21
233
+ },
234
+ {
235
+ left: {
236
+ type: "wheat",
237
+ crowns: 1
238
+ },
239
+ right: {
240
+ type: "swamp",
241
+ crowns: 0
242
+ },
243
+ number: 22
244
+ },
245
+ {
246
+ left: {
247
+ type: "wheat",
248
+ crowns: 1
249
+ },
250
+ right: {
251
+ type: "mine",
252
+ crowns: 0
253
+ },
254
+ number: 23
255
+ },
256
+ {
257
+ left: {
258
+ type: "forest",
259
+ crowns: 1
260
+ },
261
+ right: {
262
+ type: "wheat",
263
+ crowns: 0
264
+ },
265
+ number: 24
266
+ },
267
+ {
268
+ left: {
269
+ type: "forest",
270
+ crowns: 1
271
+ },
272
+ right: {
273
+ type: "wheat",
274
+ crowns: 0
275
+ },
276
+ number: 25
277
+ },
278
+ {
279
+ left: {
280
+ type: "forest",
281
+ crowns: 1
282
+ },
283
+ right: {
284
+ type: "wheat",
285
+ crowns: 0
286
+ },
287
+ number: 26
288
+ },
289
+ {
290
+ left: {
291
+ type: "forest",
292
+ crowns: 1
293
+ },
294
+ right: {
295
+ type: "wheat",
296
+ crowns: 0
297
+ },
298
+ number: 27
299
+ },
300
+ {
301
+ left: {
302
+ type: "forest",
303
+ crowns: 1
304
+ },
305
+ right: {
306
+ type: "water",
307
+ crowns: 0
308
+ },
309
+ number: 28
310
+ },
311
+ {
312
+ left: {
313
+ type: "forest",
314
+ crowns: 1
315
+ },
316
+ right: {
317
+ type: "grass",
318
+ crowns: 0
319
+ },
320
+ number: 29
321
+ },
322
+ {
323
+ left: {
324
+ type: "water",
325
+ crowns: 1
326
+ },
327
+ right: {
328
+ type: "wheat",
329
+ crowns: 0
330
+ },
331
+ number: 30
332
+ },
333
+ {
334
+ left: {
335
+ type: "water",
336
+ crowns: 1
337
+ },
338
+ right: {
339
+ type: "wheat",
340
+ crowns: 0
341
+ },
342
+ number: 31
343
+ },
344
+ {
345
+ left: {
346
+ type: "water",
347
+ crowns: 1
348
+ },
349
+ right: {
350
+ type: "forest",
351
+ crowns: 0
352
+ },
353
+ number: 32
354
+ },
355
+ {
356
+ left: {
357
+ type: "water",
358
+ crowns: 1
359
+ },
360
+ right: {
361
+ type: "forest",
362
+ crowns: 0
363
+ },
364
+ number: 33
365
+ },
366
+ {
367
+ left: {
368
+ type: "water",
369
+ crowns: 1
370
+ },
371
+ right: {
372
+ type: "forest",
373
+ crowns: 0
374
+ },
375
+ number: 34
376
+ },
377
+ {
378
+ left: {
379
+ type: "water",
380
+ crowns: 1
381
+ },
382
+ right: {
383
+ type: "forest",
384
+ crowns: 0
385
+ },
386
+ number: 35
387
+ },
388
+ {
389
+ left: {
390
+ type: "wheat",
391
+ crowns: 0
392
+ },
393
+ right: {
394
+ type: "grass",
395
+ crowns: 1
396
+ },
397
+ number: 36
398
+ },
399
+ {
400
+ left: {
401
+ type: "water",
402
+ crowns: 0
403
+ },
404
+ right: {
405
+ type: "grass",
406
+ crowns: 1
407
+ },
408
+ number: 37
409
+ },
410
+ {
411
+ left: {
412
+ type: "wheat",
413
+ crowns: 0
414
+ },
415
+ right: {
416
+ type: "swamp",
417
+ crowns: 1
418
+ },
419
+ number: 38
420
+ },
421
+ {
422
+ left: {
423
+ type: "grass",
424
+ crowns: 0
425
+ },
426
+ right: {
427
+ type: "swamp",
428
+ crowns: 0
429
+ },
430
+ number: 39
431
+ },
432
+ {
433
+ left: {
434
+ type: "mine",
435
+ crowns: 1
436
+ },
437
+ right: {
438
+ type: "wheat",
439
+ crowns: 0
440
+ },
441
+ number: 40
442
+ },
443
+ {
444
+ left: {
445
+ type: "wheat",
446
+ crowns: 0
447
+ },
448
+ right: {
449
+ type: "grass",
450
+ crowns: 2
451
+ },
452
+ number: 41
453
+ },
454
+ {
455
+ left: {
456
+ type: "water",
457
+ crowns: 0
458
+ },
459
+ right: {
460
+ type: "grass",
461
+ crowns: 2
462
+ },
463
+ number: 42
464
+ },
465
+ {
466
+ left: {
467
+ type: "wheat",
468
+ crowns: 0
469
+ },
470
+ right: {
471
+ type: "swamp",
472
+ crowns: 2
473
+ },
474
+ number: 43
475
+ },
476
+ {
477
+ left: {
478
+ type: "grass",
479
+ crowns: 0
480
+ },
481
+ right: {
482
+ type: "swamp",
483
+ crowns: 2
484
+ },
485
+ number: 44
486
+ },
487
+ {
488
+ left: {
489
+ type: "mine",
490
+ crowns: 2
491
+ },
492
+ right: {
493
+ type: "wheat",
494
+ crowns: 0
495
+ },
496
+ number: 45
497
+ },
498
+ {
499
+ left: {
500
+ type: "swamp",
501
+ crowns: 0
502
+ },
503
+ right: {
504
+ type: "mine",
505
+ crowns: 2
506
+ },
507
+ number: 46
508
+ },
509
+ {
510
+ left: {
511
+ type: "swamp",
512
+ crowns: 0
513
+ },
514
+ right: {
515
+ type: "mine",
516
+ crowns: 2
517
+ },
518
+ number: 47
519
+ },
520
+ {
521
+ left: {
522
+ type: "wheat",
523
+ crowns: 0
524
+ },
525
+ right: {
526
+ type: "mine",
527
+ crowns: 3
528
+ },
529
+ number: 48
530
+ }
531
+ ];
532
+
533
+ // src/infrastructure/repositories/inMemoryDominoes.ts
534
+ var inMemoryDominoes = () => {
535
+ const dominoes = [];
536
+ dominoes_default.forEach((domino) => {
537
+ dominoes.push({
538
+ left: {
539
+ type: domino.left.type,
540
+ crowns: domino.left.crowns
541
+ },
542
+ right: {
543
+ type: domino.right.type,
544
+ crowns: domino.right.crowns
545
+ },
546
+ number: domino.number
547
+ });
548
+ });
549
+ return {
550
+ getAll: () => {
551
+ return dominoes;
552
+ }
553
+ };
554
+ };
555
+ var inMemoryDominoes_default = inMemoryDominoes;
556
+
557
+ // src/domain/entities/game.ts
558
+ var availableMode = ["Classic"];
559
+
560
+ // src/domain/useCases/game/init.ts
561
+ var init = (dependencies) => () => {
562
+ const dominoes = dependencies.dominoesRepository.getAll();
563
+ const id = dependencies.uuidMethod();
564
+ const state = {
565
+ id,
566
+ dominoes,
567
+ currentDominoes: [],
568
+ players: [],
569
+ kings: [],
570
+ turn: 0,
571
+ maxTurns: 0,
572
+ maxDominoes: 0,
573
+ dominoesPerTurn: 0,
574
+ order: {}
575
+ };
576
+ return state;
577
+ };
578
+
579
+ // src/domain/entities/kingdom.ts
580
+ var createEmptyKingdom = () => {
581
+ const gridSize = 9;
582
+ const emptyTile = { type: "empty", crowns: 0 };
583
+ return Array.from(
584
+ { length: gridSize },
585
+ () => Array.from({ length: gridSize }, () => emptyTile)
586
+ );
587
+ };
588
+ var createKingdomWithCastle = () => {
589
+ const kingdom2 = createEmptyKingdom();
590
+ return placeTile(kingdom2, { x: 4, y: 4 }, { type: "castle", crowns: 0 });
591
+ };
592
+ var placeTile = (kingdom2, position, tile) => {
593
+ const newRow = [...kingdom2[position.y]];
594
+ newRow[position.x] = tile;
595
+ return [
596
+ ...kingdom2.slice(0, position.y),
597
+ newRow,
598
+ ...kingdom2.slice(position.y + 1)
599
+ ];
600
+ };
601
+ var getTile = (grid, position) => {
602
+ const tile = grid[position.y]?.[position.x];
603
+ if (tile === void 0) {
604
+ throw new Error("Invalid placement (not fit into the grid)");
605
+ }
606
+ return tile;
607
+ };
608
+ var calculateDominoPosition = (position, orientation, rotation, domino) => {
609
+ let firstTile;
610
+ let secondTile;
611
+ if (orientation === "horizontal") {
612
+ if (rotation === 0) {
613
+ firstTile = {
614
+ tile: domino.left,
615
+ position: {
616
+ x: position.x,
617
+ y: position.y
618
+ }
619
+ };
620
+ secondTile = {
621
+ tile: domino.right,
622
+ position: {
623
+ x: position.x + 1,
624
+ y: position.y
625
+ }
626
+ };
627
+ } else {
628
+ firstTile = {
629
+ tile: domino.right,
630
+ position: {
631
+ x: position.x,
632
+ y: position.y
633
+ }
634
+ };
635
+ secondTile = {
636
+ tile: domino.left,
637
+ position: {
638
+ x: position.x + 1,
639
+ y: position.y
640
+ }
641
+ };
642
+ }
643
+ } else {
644
+ if (rotation === 0) {
645
+ firstTile = {
646
+ tile: domino.left,
647
+ position: {
648
+ x: position.x,
649
+ y: position.y
650
+ }
651
+ };
652
+ secondTile = {
653
+ tile: domino.right,
654
+ position: {
655
+ x: position.x,
656
+ y: position.y + 1
657
+ }
658
+ };
659
+ } else {
660
+ firstTile = {
661
+ tile: domino.right,
662
+ position: {
663
+ x: position.x,
664
+ y: position.y
665
+ }
666
+ };
667
+ secondTile = {
668
+ tile: domino.left,
669
+ position: {
670
+ x: position.x,
671
+ y: position.y + 1
672
+ }
673
+ };
674
+ }
675
+ }
676
+ return [firstTile, secondTile];
677
+ };
678
+ var placeDomino = (kingdom2, position, orientation, rotation, domino) => {
679
+ const [firstTile, secondTile] = calculateDominoPosition(
680
+ position,
681
+ orientation,
682
+ rotation,
683
+ domino
684
+ );
685
+ if (!isFreePlace(kingdom2, firstTile.position, secondTile.position)) {
686
+ throw new Error("Invalid placement (not free place)");
687
+ }
688
+ if (!isFitIntoTheGrid(kingdom2, [firstTile, secondTile])) {
689
+ throw new Error("Invalid placement (not fit into the grid)");
690
+ }
691
+ const adjacentTiles = isAdjacent(
692
+ kingdom2,
693
+ firstTile.position,
694
+ secondTile.position
695
+ );
696
+ if (adjacentTiles.length === 0) {
697
+ throw new Error("Invalid placement (no adjacent)");
698
+ }
699
+ const hasValidAdjacentTiles = hasValidAdjacent(adjacentTiles, [
700
+ firstTile.tile,
701
+ secondTile.tile
702
+ ]);
703
+ if (!hasValidAdjacentTiles) {
704
+ throw new Error("Invalid placement (no valid adjacent)");
705
+ }
706
+ return placeTiles(kingdom2, [firstTile, secondTile]);
707
+ };
708
+ var placeTiles = (kingdom2, tiles) => {
709
+ return tiles.reduce(
710
+ (newKingdom, { tile, position }) => placeTile(newKingdom, position, tile),
711
+ kingdom2
712
+ );
713
+ };
714
+ var isFreePlace = (kingdom2, firstPosition, secondPosition) => {
715
+ const firstTile = getTile(kingdom2, firstPosition);
716
+ const secondTile = getTile(kingdom2, secondPosition);
717
+ if (firstTile.type !== "empty" || secondTile.type !== "empty") {
718
+ return false;
719
+ }
720
+ return true;
721
+ };
722
+ var isAdjacent = (kingdom2, firstPosition, secondPosition) => {
723
+ const xFirstPosition = firstPosition.x;
724
+ const yFirstPosition = firstPosition.y;
725
+ const xSecondPosition = secondPosition.x;
726
+ const ySecondPosition = secondPosition.y;
727
+ const adjacentTiles = [];
728
+ const adjacentTilesKeys = [
729
+ { x: xFirstPosition - 1, y: yFirstPosition },
730
+ { x: xFirstPosition, y: yFirstPosition - 1 },
731
+ { x: xFirstPosition + 1, y: yFirstPosition },
732
+ { x: xFirstPosition, y: yFirstPosition + 1 },
733
+ { x: xSecondPosition - 1, y: ySecondPosition },
734
+ { x: xSecondPosition, y: ySecondPosition - 1 },
735
+ { x: xSecondPosition + 1, y: ySecondPosition },
736
+ { x: xSecondPosition, y: ySecondPosition + 1 }
737
+ ];
738
+ adjacentTilesKeys.splice(
739
+ adjacentTilesKeys.findIndex((pos) => {
740
+ return pos.x === xFirstPosition && pos.y === yFirstPosition;
741
+ }),
742
+ 1
743
+ );
744
+ adjacentTilesKeys.splice(
745
+ adjacentTilesKeys.findIndex((pos) => {
746
+ return pos.x === xSecondPosition && pos.y === ySecondPosition;
747
+ }),
748
+ 1
749
+ );
750
+ adjacentTilesKeys.forEach((key) => {
751
+ const tile = getTile(kingdom2, key);
752
+ if (tile) {
753
+ adjacentTiles.push(tile);
754
+ }
755
+ });
756
+ return adjacentTiles;
757
+ };
758
+ var hasValidAdjacent = (adjacentTiles, tiles) => {
759
+ return adjacentTiles.some((adjacentTile) => {
760
+ return tiles.some((tile) => {
761
+ return tile.type === adjacentTile.type || adjacentTile.type === "castle";
762
+ });
763
+ });
764
+ };
765
+ var isFitIntoTheGrid = (grid, positions) => {
766
+ const maxSize = 5;
767
+ const simulateNewGrid = [...grid];
768
+ simulateNewGrid[positions[0].position.y][positions[0].position.x] = positions[0].tile;
769
+ simulateNewGrid[positions[1].position.y][positions[1].position.x] = positions[1].tile;
770
+ const lines = simulateNewGrid.map(
771
+ (line) => line.filter((tile) => tile.type !== "empty")
772
+ );
773
+ const columns = simulateNewGrid[0].map(
774
+ (_, index) => simulateNewGrid.map((line) => line[index]).filter((tile) => tile?.type !== "empty")
775
+ );
776
+ const linesLength = lines.map((line) => line.length);
777
+ const columnsLength = columns.map((line) => line.length);
778
+ const maxLineLength = Math.max(...linesLength);
779
+ const maxColumnLength = Math.max(...columnsLength);
780
+ if (maxLineLength > maxSize || maxColumnLength > maxSize) {
781
+ return false;
782
+ }
783
+ return true;
784
+ };
785
+ var kingdom = {
786
+ createEmptyKingdom,
787
+ createKingdomWithCastle,
788
+ getTile,
789
+ placeDomino
790
+ };
791
+ var kingdom_default = kingdom;
792
+
793
+ // src/domain/useCases/game/setup.ts
794
+ var setup = (dependencies) => (payload) => {
795
+ const { state, players } = payload;
796
+ if (!players) {
797
+ throw new Error("There must be at least 2 players");
798
+ }
799
+ if (players.length > 4) {
800
+ throw new Error("There must be no more than 4 players");
801
+ }
802
+ if (players.length < 2) {
803
+ throw new Error("There must be at least 2 players");
804
+ }
805
+ const { dominoes } = state;
806
+ const { randomMethod, uuidMethod } = dependencies;
807
+ const { maxDominoes, dominoesPerTurn, maxTurns } = rules[players.length];
808
+ const shuffledDominoes = randomMethod(dominoes);
809
+ shuffledDominoes.splice(maxDominoes);
810
+ const newPlayers = players.map((player) => {
811
+ return {
812
+ ...player,
813
+ kingdom: kingdom_default.createKingdomWithCastle(),
814
+ id: uuidMethod()
815
+ };
816
+ });
817
+ let newKings;
818
+ if (newPlayers.length === 2) {
819
+ newKings = [
820
+ {
821
+ id: uuidMethod(),
822
+ playerId: newPlayers[0].id,
823
+ order: 1,
824
+ turnEnded: false,
825
+ hasPick: false,
826
+ hasPlace: false
827
+ },
828
+ {
829
+ id: uuidMethod(),
830
+ playerId: newPlayers[0].id,
831
+ order: 2,
832
+ turnEnded: false,
833
+ hasPick: false,
834
+ hasPlace: false
835
+ },
836
+ {
837
+ id: uuidMethod(),
838
+ playerId: newPlayers[1].id,
839
+ order: 3,
840
+ turnEnded: false,
841
+ hasPick: false,
842
+ hasPlace: false
843
+ },
844
+ {
845
+ id: uuidMethod(),
846
+ playerId: newPlayers[1].id,
847
+ order: 4,
848
+ turnEnded: false,
849
+ hasPick: false,
850
+ hasPlace: false
851
+ }
852
+ ];
853
+ } else {
854
+ newKings = newPlayers.map((player, index) => {
855
+ return {
856
+ id: uuidMethod(),
857
+ playerId: player.id,
858
+ order: index + 1,
859
+ turnEnded: false,
860
+ hasPick: false,
861
+ hasPlace: false
862
+ };
863
+ });
864
+ }
865
+ const kingsWithOrder = randomMethod(newKings);
866
+ kingsWithOrder.forEach((king, index) => {
867
+ king.order = index + 1;
868
+ });
869
+ kingsWithOrder.sort((a, b) => a.order - b.order);
870
+ const newState = {
871
+ ...state,
872
+ dominoes: shuffledDominoes,
873
+ players: newPlayers,
874
+ kings: kingsWithOrder,
875
+ maxTurns,
876
+ maxDominoes,
877
+ dominoesPerTurn,
878
+ turn: 0
879
+ };
880
+ return newState;
881
+ };
882
+
883
+ // src/domain/useCases/game/startTurn.ts
884
+ var startTurn = (payload) => {
885
+ const { state } = payload;
886
+ const turn = state.turn + 1;
887
+ const kings = state.kings;
888
+ kings.forEach((king) => {
889
+ king.turnEnded = false;
890
+ king.hasPick = false;
891
+ king.hasPlace = false;
892
+ });
893
+ const updatedState = {
894
+ ...state,
895
+ kings,
896
+ turn
897
+ };
898
+ return { game: updatedState };
899
+ };
900
+
901
+ // src/domain/useCases/game/pick.ts
902
+ var pick = (payload) => {
903
+ const { kingId, data } = payload;
904
+ const { state, dominoPick } = data;
905
+ const { currentDominoes, kings } = state;
906
+ if (!isKingTurn(state, kingId)) {
907
+ throw new Error("It is not your turn");
908
+ }
909
+ const king = kings.find((king2) => king2.id === kingId);
910
+ if (king?.hasPick) {
911
+ throw new Error("You have already picked");
912
+ }
913
+ const domino = checkValidityDomino(state, dominoPick);
914
+ const isError = (domino2) => {
915
+ return domino2.error !== void 0;
916
+ };
917
+ if (isError(domino)) {
918
+ throw new Error(domino.error);
919
+ }
920
+ const updatedCurrentDominoes = currentDominoes.map((domino2) => {
921
+ if (domino2.domino.number === dominoPick) {
922
+ domino2.picked = true;
923
+ domino2.kingId = kingId;
924
+ }
925
+ return domino2;
926
+ });
927
+ const updatedKings = kings.map((king2) => {
928
+ if (king2.id === kingId) {
929
+ king2.hasPick = true;
930
+ king2.turnEnded = true;
931
+ king2.dominoPicked = domino.domino;
932
+ }
933
+ return king2;
934
+ });
935
+ const updatedState = {
936
+ ...state,
937
+ currentDominoes: updatedCurrentDominoes,
938
+ kings: updatedKings
939
+ };
940
+ return updatedState;
941
+ };
942
+
943
+ // src/domain/useCases/game/place.ts
944
+ var place = (payload) => {
945
+ const { kingId, data } = payload;
946
+ const { state, position, orientation, rotation } = data;
947
+ const currentKing = state.kings.find((king) => king.id === kingId);
948
+ const currentPlayer = state.players.find(
949
+ (player) => player.id === currentKing?.playerId
950
+ );
951
+ const currentKingdom = currentPlayer?.kingdom;
952
+ if (!currentKingdom) {
953
+ throw new Error("Kingdom not found");
954
+ }
955
+ const domino = currentKing?.dominoPicked;
956
+ if (!domino) {
957
+ throw new Error("Domino not found");
958
+ }
959
+ kingdom_default.placeDomino(currentKingdom, position, orientation, rotation, domino);
960
+ currentPlayer.kingdom = currentKingdom;
961
+ currentKing.hasPlace = true;
962
+ const newState = {
963
+ ...state,
964
+ kings: state.kings.map((king) => {
965
+ if (king.id === kingId) {
966
+ return currentKing;
967
+ }
968
+ return king;
969
+ })
970
+ };
971
+ return newState;
972
+ };
973
+
974
+ // src/domain/useCases/game/order.ts
975
+ var definePlayerOrder = (payload) => {
976
+ const { state } = payload;
977
+ const { kings, currentDominoes } = state;
978
+ const allKingsHavePlayed = kings.every((king) => king.turnEnded);
979
+ if (!allKingsHavePlayed) {
980
+ throw new Error("Not all kings have played");
981
+ }
982
+ const updatedKings = kings.map((king) => {
983
+ return {
984
+ ...king,
985
+ order: currentDominoes.find((domino) => domino.kingId === king.id)?.position || 0
986
+ };
987
+ });
988
+ const order = updatedKings.reduce((acc, king) => {
989
+ return {
990
+ ...acc,
991
+ [king.order]: king.id
992
+ };
993
+ }, {});
994
+ const newState = {
995
+ ...state,
996
+ kings: updatedKings,
997
+ order
998
+ };
999
+ return newState;
1000
+ };
1001
+
1002
+ // src/domain/useCases/game/draw.ts
1003
+ var draw = (payload) => {
1004
+ const { state } = payload;
1005
+ const dominoesCopy = [...state.dominoes];
1006
+ const dominoesDrawn = dominoesCopy.splice(0, state.dominoesPerTurn);
1007
+ dominoesDrawn.sort((a, b) => a.number - b.number);
1008
+ const newState = {
1009
+ ...state,
1010
+ dominoes: dominoesCopy,
1011
+ currentDominoes: dominoesDrawn.map((domino, index) => {
1012
+ return {
1013
+ domino,
1014
+ picked: false,
1015
+ kingId: null,
1016
+ position: index + 1
1017
+ };
1018
+ })
1019
+ };
1020
+ return newState;
1021
+ };
1022
+
1023
+ // src/domain/useCases/game/scoring.ts
1024
+ var calculateScore = (kingdom2) => {
1025
+ const visited = kingdom2.map((row) => row.map(() => false));
1026
+ const properties = [];
1027
+ const directions = [
1028
+ [-1, 0],
1029
+ [1, 0],
1030
+ [0, -1],
1031
+ [0, 1]
1032
+ ];
1033
+ const markZone = (x, y, type, crowns) => {
1034
+ if (x < 0 || y < 0 || x >= kingdom2[0].length || y >= kingdom2.length || visited[y][x] || kingdom2[y][x].type !== type || kingdom2[y][x].type === "empty" || kingdom2[y][x].type === "castle") {
1035
+ return;
1036
+ }
1037
+ visited[y][x] = true;
1038
+ const currentZone = properties.find(
1039
+ (property) => property.type === type && property.tiles.some(([tx, ty]) => {
1040
+ for (let [dx, dy] of directions) {
1041
+ if (tx + dx === x && ty + dy === y) {
1042
+ return true;
1043
+ }
1044
+ }
1045
+ return false;
1046
+ })
1047
+ );
1048
+ if (currentZone) {
1049
+ currentZone.crowns += crowns;
1050
+ currentZone.size++;
1051
+ currentZone.tiles.push([x, y]);
1052
+ } else {
1053
+ properties.push({ type, crowns, size: 1, tiles: [[x, y]] });
1054
+ }
1055
+ directions.forEach(([dx, dy]) => {
1056
+ const nx = x + dx;
1057
+ const ny = y + dy;
1058
+ if (nx >= 0 && ny >= 0 && nx < kingdom2[0].length && ny < kingdom2.length && kingdom2[ny][nx].type === type) {
1059
+ markZone(nx, ny, kingdom2[ny][nx].type, kingdom2[ny][nx].crowns);
1060
+ }
1061
+ });
1062
+ };
1063
+ kingdom2.forEach((row, y) => {
1064
+ row.forEach((tile, x) => {
1065
+ if (!visited[y][x]) {
1066
+ markZone(x, y, tile.type, tile.crowns);
1067
+ }
1068
+ });
1069
+ });
1070
+ if (properties.length === 0) {
1071
+ return {
1072
+ score: 0,
1073
+ maxPropertiesSize: 0,
1074
+ totalCrowns: 0
1075
+ };
1076
+ }
1077
+ const score = properties.reduce(
1078
+ (score2, property) => score2 + property.crowns * property.size,
1079
+ 0
1080
+ );
1081
+ const maxPropertiesSize = Math.max(
1082
+ ...properties.map((property) => property.size ?? 0)
1083
+ );
1084
+ const totalCrowns = properties.reduce(
1085
+ (total, property) => total + property.crowns,
1086
+ 0
1087
+ );
1088
+ return {
1089
+ score,
1090
+ maxPropertiesSize,
1091
+ totalCrowns
1092
+ };
1093
+ };
1094
+
1095
+ // src/domain/useCases/game/pass.ts
1096
+ var pass = (payload) => {
1097
+ const { kingId, data } = payload;
1098
+ const { state } = data;
1099
+ const currentKing = state.kings.find((king) => king.id === kingId);
1100
+ if (!currentKing) {
1101
+ throw new Error("King not found");
1102
+ }
1103
+ currentKing.hasPlace = true;
1104
+ const newState = {
1105
+ ...state,
1106
+ kings: state.kings.map((king) => {
1107
+ if (king.id === kingId) {
1108
+ return currentKing;
1109
+ }
1110
+ return king;
1111
+ })
1112
+ };
1113
+ return newState;
1114
+ };
1115
+
1116
+ // src/domain/useCases/game/game.ts
1117
+ var gameStep = (dependencies) => {
1118
+ return {
1119
+ init: init(dependencies),
1120
+ setup: setup(dependencies),
1121
+ startTurn,
1122
+ pick,
1123
+ place,
1124
+ pass,
1125
+ definePlayerOrder,
1126
+ draw,
1127
+ calculateScore
1128
+ };
1129
+ };
1130
+ var isKingTurn = (state, kingId) => {
1131
+ const { kings, currentDominoes } = state;
1132
+ const currentKingOrder = kings.find((king) => king.id === kingId)?.order;
1133
+ const pickedDominoes = currentDominoes.filter(
1134
+ (currentDomino) => currentDomino.picked
1135
+ );
1136
+ if (currentKingOrder !== pickedDominoes.length + 1) {
1137
+ return false;
1138
+ }
1139
+ return true;
1140
+ };
1141
+ var checkValidityDomino = (state, dominoPick) => {
1142
+ const { currentDominoes } = state;
1143
+ const domino = currentDominoes.find(
1144
+ (currentDomino) => currentDomino.domino.number === dominoPick
1145
+ );
1146
+ if (!domino) {
1147
+ const error = {
1148
+ error: "Domino not found"
1149
+ };
1150
+ return error;
1151
+ }
1152
+ if (domino.picked) {
1153
+ const error = {
1154
+ error: "Domino already picked"
1155
+ };
1156
+ return error;
1157
+ }
1158
+ return domino;
1159
+ };
1160
+ var rules = {
1161
+ 2: {
1162
+ kings: 2,
1163
+ maxDominoes: 24,
1164
+ dominoesPerTurn: 4,
1165
+ maxTurns: 6
1166
+ },
1167
+ 3: {
1168
+ kings: 1,
1169
+ maxDominoes: 36,
1170
+ dominoesPerTurn: 3,
1171
+ maxTurns: 12
1172
+ },
1173
+ 4: {
1174
+ kings: 1,
1175
+ maxDominoes: 48,
1176
+ dominoesPerTurn: 4,
1177
+ maxTurns: 12
1178
+ }
1179
+ };
1180
+ var game_default = gameStep;
1181
+
1182
+ // src/domain/useCases/game/result.ts
1183
+ var result = (scores) => {
1184
+ scores.sort((a, b) => {
1185
+ if (a.details.score !== b.details.score) {
1186
+ return b.details.score - a.details.score;
1187
+ }
1188
+ if (a.details.maxPropertiesSize !== b.details.maxPropertiesSize) {
1189
+ return b.details.maxPropertiesSize - a.details.maxPropertiesSize;
1190
+ }
1191
+ return b.details.totalCrowns - a.details.totalCrowns;
1192
+ });
1193
+ const result2 = [];
1194
+ let isTie = false;
1195
+ result2.push({
1196
+ ...scores[0],
1197
+ position: 1
1198
+ });
1199
+ for (let i = 1; i < scores.length; i++) {
1200
+ const currentScore = scores[i];
1201
+ const previousScore = scores[i - 1];
1202
+ if (previousScore && currentScore && currentScore.details.score === previousScore.details.score && currentScore.details.maxPropertiesSize === previousScore.details.maxPropertiesSize && currentScore.details.totalCrowns === previousScore.details.totalCrowns) {
1203
+ isTie = true;
1204
+ }
1205
+ if (isTie) {
1206
+ result2.push({
1207
+ ...currentScore,
1208
+ position: result2[i - 1].position
1209
+ });
1210
+ } else {
1211
+ result2.push({
1212
+ ...currentScore,
1213
+ position: i + 1
1214
+ });
1215
+ }
1216
+ isTie = false;
1217
+ }
1218
+ return result2;
1219
+ };
1220
+
1221
+ // src/application/engine/index.ts
1222
+ var gameEngine = () => {
1223
+ const dependencies = {
1224
+ dominoesRepository: inMemoryDominoes_default(),
1225
+ uuidMethod: () => `uuid-${Math.random()}`,
1226
+ randomMethod: (array) => array
1227
+ };
1228
+ const {
1229
+ init: init2,
1230
+ setup: setup2,
1231
+ startTurn: startTurn2,
1232
+ pick: pick2,
1233
+ place: place2,
1234
+ pass: pass2,
1235
+ definePlayerOrder: definePlayerOrder2,
1236
+ draw: draw2,
1237
+ calculateScore: calculateScore2
1238
+ } = game_default(dependencies);
1239
+ const getMode = () => {
1240
+ return availableMode;
1241
+ };
1242
+ const setMode = (mode, game) => {
1243
+ return game;
1244
+ };
1245
+ const getRules = (mode) => {
1246
+ return [];
1247
+ };
1248
+ const setRules = (rules2, game) => {
1249
+ return game;
1250
+ };
1251
+ const start = (game, players) => {
1252
+ const setupState = setup2({
1253
+ state: game,
1254
+ players
1255
+ });
1256
+ const drawState = draw2({ state: setupState });
1257
+ return {
1258
+ nextKing: drawState.kings[0].id,
1259
+ nextAction: "pick",
1260
+ game: drawState
1261
+ };
1262
+ };
1263
+ const passTurn = (game, kingId) => {
1264
+ const updatedGame = pass2({
1265
+ kingId,
1266
+ action: "pass",
1267
+ data: {
1268
+ state: game
1269
+ }
1270
+ });
1271
+ const resp = defineNextAction(updatedGame, "pass", kingId);
1272
+ return resp;
1273
+ };
1274
+ const placeDomino2 = (game, kingId, position, orientation, rotation) => {
1275
+ const updatedGame = place2({
1276
+ kingId,
1277
+ action: "place",
1278
+ data: {
1279
+ state: game,
1280
+ position,
1281
+ orientation,
1282
+ rotation
1283
+ }
1284
+ });
1285
+ const resp = defineNextAction(updatedGame, "place", kingId);
1286
+ return resp;
1287
+ };
1288
+ const pickDomino = (game, kingId, dominoPick) => {
1289
+ const updatedGame = pick2({
1290
+ kingId,
1291
+ action: "pick",
1292
+ data: {
1293
+ state: game,
1294
+ dominoPick
1295
+ }
1296
+ });
1297
+ const resp = defineNextAction(updatedGame, "pick", kingId);
1298
+ return resp;
1299
+ };
1300
+ const prepareNextTurn = (game) => {
1301
+ const updatedOrder = definePlayerOrder2({ state: game });
1302
+ const updateDraw = draw2({ state: updatedOrder });
1303
+ const updateTurn = startTurn2({ state: updateDraw });
1304
+ if (updateTurn.game.turn > updateTurn.game.maxTurns) {
1305
+ throw new Error("Game is over");
1306
+ }
1307
+ return updateTurn.game;
1308
+ };
1309
+ const defineNextAction = (game, currentAction, currentKingId) => {
1310
+ const { kings, turn } = game;
1311
+ if (turn === 0) {
1312
+ const nextKing2 = kings.find((king) => !king.hasPick);
1313
+ if (!nextKing2) {
1314
+ const newState = prepareNextTurn(game);
1315
+ return {
1316
+ nextKing: newState.kings[0].id,
1317
+ nextAction: "place",
1318
+ game: newState
1319
+ };
1320
+ }
1321
+ return {
1322
+ nextKing: nextKing2.id,
1323
+ nextAction: "pick",
1324
+ game
1325
+ };
1326
+ }
1327
+ if (currentAction === "place" || currentAction === "pass") {
1328
+ if (game.turn === game.maxTurns) {
1329
+ const nextKing2 = kings.find((king) => !king.hasPlace);
1330
+ if (!nextKing2) {
1331
+ return {
1332
+ nextKing: "none",
1333
+ nextAction: "end",
1334
+ game
1335
+ };
1336
+ }
1337
+ return {
1338
+ nextKing: nextKing2.id,
1339
+ nextAction: "place",
1340
+ game
1341
+ };
1342
+ }
1343
+ return {
1344
+ nextKing: currentKingId,
1345
+ nextAction: "pick",
1346
+ game
1347
+ };
1348
+ }
1349
+ const allKingsHavePicked = kings.every((king) => king.hasPick);
1350
+ if (allKingsHavePicked) {
1351
+ const newState = prepareNextTurn(game);
1352
+ return {
1353
+ nextKing: newState.order["1"],
1354
+ nextAction: "place",
1355
+ game: newState
1356
+ };
1357
+ }
1358
+ const nextKing = kings.find((king) => !king.hasPlace);
1359
+ return {
1360
+ nextKing: nextKing.id,
1361
+ nextAction: "place",
1362
+ game
1363
+ };
1364
+ };
1365
+ const endGame = (game) => {
1366
+ const players = game.players;
1367
+ const scores = [];
1368
+ for (let player of players) {
1369
+ const score = calculateScore2(player.kingdom);
1370
+ scores.push({
1371
+ playerId: player.id,
1372
+ playerName: player.name,
1373
+ details: score
1374
+ });
1375
+ }
1376
+ const finalResult = result(scores);
1377
+ return {
1378
+ result: finalResult,
1379
+ game
1380
+ };
1381
+ };
1382
+ return {
1383
+ init: init2,
1384
+ getMode,
1385
+ setMode,
1386
+ getRules,
1387
+ setRules,
1388
+ start,
1389
+ pass: passTurn,
1390
+ placeDomino: placeDomino2,
1391
+ pickDomino,
1392
+ endGame
1393
+ };
1394
+ };
1395
+ var engine_default = gameEngine;
1396
+
1397
+ // src/index.ts
1398
+ var src_default = engine_default;
1399
+ export {
1400
+ src_default as default
1401
+ };
1402
+ //# sourceMappingURL=index.js.map