From ab94ee431ce3757a97fec44b61ffe601925ae1be Mon Sep 17 00:00:00 2001 From: Andrew Rosborough Date: Sat, 31 Dec 2022 17:00:40 -0500 Subject: [PATCH 01/16] Initial prototype. --- src/App.vue | 53 ++++++++++++++++++++++++++------- src/components/CasinoTable.vue | 40 +++++++++++++++++++------ src/components/DurakPlayer.vue | 45 ++++++++++++++++++++++++++++ src/main.ts | 5 ++++ src/stores/aleo_casino_table.ts | 40 +++++++++++++++++++++++++ src/stores/hand.ts | 18 +++++++++++ src/stores/player.ts | 4 ++- src/stores/table.ts | 25 ---------------- src/stores/talon.ts | 18 +++++++++++ src/views/DurakView.vue | 19 ++---------- 10 files changed, 205 insertions(+), 62 deletions(-) create mode 100644 src/components/DurakPlayer.vue create mode 100644 src/stores/aleo_casino_table.ts delete mode 100644 src/stores/table.ts diff --git a/src/App.vue b/src/App.vue index 1829731..2c1df4a 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,4 +1,4 @@ - diff --git a/src/main.ts b/src/main.ts index bc8a836..e66d7ba 100644 --- a/src/main.ts +++ b/src/main.ts @@ -5,9 +5,14 @@ import App from "./App.vue"; import router from "./router"; import "./assets/main.css"; +import "@demox-labs/aleo-wallet-adapter-reactui/styles.css"; const app = createApp(App); +app.component("RouterLink", () => import("vue-router")); +app.component("RouterView", () => import("vue-router")); +app.component("IntroMessage", () => import("./components/IntroMessage.vue")); + app.use(createPinia()); app.use(router); diff --git a/src/stores/aleo_casino_table.ts b/src/stores/aleo_casino_table.ts new file mode 100644 index 0000000..652ae59 --- /dev/null +++ b/src/stores/aleo_casino_table.ts @@ -0,0 +1,40 @@ +import { ref } from "vue"; +import { defineStore } from "pinia"; + +export interface CasinoTable { + owner: string; + gates: number; + seats: number; + seats_occupied: number; + seats_ready: number; + dealer: string; + player: string; + random_seed_hash: string; + random_seed: number; +} + +export type CasinoTableList = CasinoTable[]; + +export const useCasinoTableStore = defineStore("casinoTable", () => { + const owner = ref(""); + const gates = ref(0); + const seats = ref(0); + const seats_occupied = ref(0); + const seats_ready = ref(0); + const dealer = ref(""); + const player = ref(""); + const random_seed_hash = ref(""); + const random_seed = ref(0); + + return { + owner, + gates, + seats, + seats_occupied, + seats_ready, + dealer, + player, + random_seed_hash, + random_seed, + }; +}); diff --git a/src/stores/hand.ts b/src/stores/hand.ts index e69de29..bd862d9 100644 --- a/src/stores/hand.ts +++ b/src/stores/hand.ts @@ -0,0 +1,18 @@ +import { ref } from "vue"; +import { defineStore } from "pinia"; +import type { Card, CardList } from "./card"; +import type { Deck } from "./deck"; + +export interface Hand extends Deck { + cards: CardList; + play(card: Card): void; +} + +export const useHandStore = defineStore("hand", () => { + const cards = ref([] as CardList); + function play(card: Card) { + cards.value.splice(cards.value.indexOf(card), 1); + } + + return { cards, play }; +}); diff --git a/src/stores/player.ts b/src/stores/player.ts index 87daf87..605a17e 100644 --- a/src/stores/player.ts +++ b/src/stores/player.ts @@ -16,7 +16,9 @@ export const usePlayerStore = defineStore("player", () => { const address = ref(""); const dealer = ref(false); const ready = ref(false); + const defender = ref(false); + const attacker = ref(false); const random_seed = ref(0); - return { address, dealer, ready, random_seed }; + return { address, dealer, ready, defender, attacker, random_seed }; }); diff --git a/src/stores/table.ts b/src/stores/table.ts deleted file mode 100644 index d89cc90..0000000 --- a/src/stores/table.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ref, computed } from "vue"; -import { defineStore } from "pinia"; -import type { Player, PlayerList } from "./player"; - -export interface Table { - dealer: Player; - players: PlayerList; - seats: number; - ready_states: boolean[]; - defender: Player; - attackers: PlayerList; -} - -export type TableList = Table[]; - -export const useTableStore = defineStore("table", () => { - const dealer = ref({} as Player); - const players = ref([] as PlayerList); - const seats = ref(0); - const ready_states = computed(() => { - return players.value.map((player) => player.ready); - }); - - return { dealer, players, seats, ready_states }; -}); diff --git a/src/stores/talon.ts b/src/stores/talon.ts index e69de29..40ce845 100644 --- a/src/stores/talon.ts +++ b/src/stores/talon.ts @@ -0,0 +1,18 @@ +import { ref } from "vue"; +import { defineStore } from "pinia"; +import type { Card, CardList } from "./card"; +import type { Deck } from "./deck"; + +export interface Talon extends Deck { + cards: CardList; + take(card: Card): void; +} + +export const useHandStore = defineStore("hand", () => { + const cards = ref([] as CardList); + function play(card: Card) { + cards.value.splice(cards.value.indexOf(card), 1); + } + + return { cards, play }; +}); diff --git a/src/views/DurakView.vue b/src/views/DurakView.vue index 67b41d5..5b94425 100644 --- a/src/views/DurakView.vue +++ b/src/views/DurakView.vue @@ -1,25 +1,12 @@ diff --git a/src/components/TransactionComponent.vue b/src/components/TransactionComponent.vue new file mode 100644 index 0000000..ae207b7 --- /dev/null +++ b/src/components/TransactionComponent.vue @@ -0,0 +1,33 @@ + + + + + diff --git a/src/components/VueWalletBridge.vue b/src/components/VueWalletBridge.vue new file mode 100644 index 0000000..1d2f028 --- /dev/null +++ b/src/components/VueWalletBridge.vue @@ -0,0 +1,56 @@ + + + diff --git a/src/components/icons/IconError.vue b/src/components/icons/IconError.vue new file mode 100644 index 0000000..5000353 --- /dev/null +++ b/src/components/icons/IconError.vue @@ -0,0 +1,23 @@ + diff --git a/src/components/icons/IconFlame.vue b/src/components/icons/IconFlame.vue new file mode 100644 index 0000000..42f510d --- /dev/null +++ b/src/components/icons/IconFlame.vue @@ -0,0 +1,12 @@ + diff --git a/src/components/icons/IconValid.vue b/src/components/icons/IconValid.vue new file mode 100644 index 0000000..b2d04b8 --- /dev/null +++ b/src/components/icons/IconValid.vue @@ -0,0 +1,44 @@ + diff --git a/src/hooks/index.ts b/src/hooks/index.ts new file mode 100644 index 0000000..511e6b0 --- /dev/null +++ b/src/hooks/index.ts @@ -0,0 +1,16 @@ +// Create a Provider that can get react hooks +// This Provider will be exported as a react component, +// and all of the vue components in this Provider can get the status of react hooks + +import { useWallet } from "@demox-labs/aleo-wallet-adapter-react"; +import { createCrossingProviderForPureReactInVue } from "veaury"; + +// Execute 'useReactRouterForVue' in the setup function of the vue component to get the object returned by the incoming function +const [useReactUseWalletForVue, ReactUseWalletProviderForVue] = + createCrossingProviderForPureReactInVue(() => { + return { + wallet: useWallet(), + }; + }); + +export { useReactUseWalletForVue, ReactUseWalletProviderForVue }; diff --git a/src/main.ts b/src/main.ts index e66d7ba..6d3de51 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,19 +1,18 @@ import { createApp } from "vue"; import { createPinia } from "pinia"; +import hljsVuePlugin from "@highlightjs/vue-plugin"; import App from "./App.vue"; import router from "./router"; import "./assets/main.css"; import "@demox-labs/aleo-wallet-adapter-reactui/styles.css"; +import "highlight.js/styles/stackoverflow-light.css"; const app = createApp(App); -app.component("RouterLink", () => import("vue-router")); -app.component("RouterView", () => import("vue-router")); -app.component("IntroMessage", () => import("./components/IntroMessage.vue")); - app.use(createPinia()); app.use(router); +app.use(hljsVuePlugin); app.mount("#app"); diff --git a/src/router/index.ts b/src/router/index.ts index 142c08d..ed0df4a 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -1,5 +1,6 @@ import { createRouter, createWebHistory } from "vue-router"; import HomeView from "../views/HomeView.vue"; +import DurakView from "../views/DurakView.vue"; const router = createRouter({ history: createWebHistory(import.meta.env.BASE_URL), @@ -12,10 +13,8 @@ const router = createRouter({ { path: "/durak", name: "Дурак", - // route level code-splitting - // this generates a separate chunk (About.[hash].js) for this route - // which is lazy-loaded when the route is visited. - component: () => import("../views/DurakView.vue"), + component: DurakView, + props: true, }, ], }); diff --git a/src/stores/aleo_casino_table.ts b/src/stores/aleo_casino_table.ts index 652ae59..81dd346 100644 --- a/src/stores/aleo_casino_table.ts +++ b/src/stores/aleo_casino_table.ts @@ -1,6 +1,11 @@ import { ref } from "vue"; import { defineStore } from "pinia"; +// import { useWallet } from "@demox-labs/aleo-wallet-adapter-react"; + +// const { wallet, publicKey, sendTransaction, signAllTransactions, viewKey } = +// useWallet(); + export interface CasinoTable { owner: string; gates: number; diff --git a/src/stores/player.ts b/src/stores/player.ts index 605a17e..ec1557b 100644 --- a/src/stores/player.ts +++ b/src/stores/player.ts @@ -1,24 +1,43 @@ -import { ref } from "vue"; import { defineStore } from "pinia"; -export interface Player { +export const usePlayerStore = defineStore("player", { + // state + state: () => { + return { + playerList: [] as PlayerInfo[], + player: null as PlayerInfo | null, + }; + }, + // getters + getters: { + playerList: (state) => state.playerList, + player: (state) => state.player, + }, + // actions + actions: { + addPlayer(player: PlayerInfo) { + this.playerList.push(player); + }, + setPlayer(player: PlayerInfo) { + this.player = player; + }, + updatePlayer(player: PlayerInfo) { + this.playerList = this.playerList.map((p) => { + if (p.address === player.address) { + return player; + } + return p; + }); + }, + }, +}); + +export interface PlayerInfo { address: string; dealer: boolean; ready: boolean; defender: boolean; attacker: boolean; - random_seed: number; + random_seed_hash: string | null; + random_seed: number | null; } - -export type PlayerList = Player[]; - -export const usePlayerStore = defineStore("player", () => { - const address = ref(""); - const dealer = ref(false); - const ready = ref(false); - const defender = ref(false); - const attacker = ref(false); - const random_seed = ref(0); - - return { address, dealer, ready, defender, attacker, random_seed }; -}); diff --git a/src/stores/table_invitation.ts b/src/stores/table_invitation.ts new file mode 100644 index 0000000..c4cb855 --- /dev/null +++ b/src/stores/table_invitation.ts @@ -0,0 +1,72 @@ +import { ref, computed } from "vue"; +import { defineStore } from "pinia"; + +export interface TableInvitation { + player01: string | null; + player02: string | null; + player03: string | null; + player04: string | null; + player05: string | null; + player06: string | null; + player07: string | null; + burnToPlayer(index: number): void; +} + +export type Address = string | null; + +export const useTableInvitationStore = defineStore("table_invitation", () => { + const player00 = ref("" as Address); + const player01 = ref("" as Address); + const player02 = ref("" as Address); + const player03 = ref("" as Address); + const player04 = ref("" as Address); + const player05 = ref("" as Address); + const player06 = ref("" as Address); + const player07 = ref("" as Address); + + function set(index: number, address: string | null) { + if (index === 0) { + player00.value = address; + } + if (index === 1) { + player01.value = address; + } + if (index === 2) { + player02.value = address; + } + if (index === 3) { + player03.value = address; + } + if (index === 4) { + player04.value = address; + } + if (index === 5) { + player05.value = address; + } + if (index === 6) { + player06.value = address; + } + if (index === 7) { + player07.value = address; + } + return address; + } + + const burn_address = computed( + () => + "aleo1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq3ljyzc" as Address + ); + + return { + player00, + player01, + player02, + player03, + player04, + player05, + player06, + player07, + set, + burn_address, + }; +}); diff --git a/src/views/DurakView.vue b/src/views/DurakView.vue index 5b94425..196fc06 100644 --- a/src/views/DurakView.vue +++ b/src/views/DurakView.vue @@ -1,12 +1,32 @@ diff --git a/src/components/CasinoTableInvitation.vue b/src/components/CasinoTableInvitation.vue index 8f63340..49961f4 100644 --- a/src/components/CasinoTableInvitation.vue +++ b/src/components/CasinoTableInvitation.vue @@ -81,24 +81,32 @@ async function execute() { console.log(result.data.transaction_id); // Then get the transaction and store the relevant results // TODO: This fails - // const transaction_id = result.data.transaction_id; - // const uri = "/api/testnet3/transaction/" + transaction_id; - // try { - // const tx_result = await axios.get(uri); - // console.log(tx_result); - // } catch (e) { - // console.log(e); - // } + const transaction_id = result.data.transaction_id; + const uri = "/api/testnet3/transaction/" + transaction_id; + try { + const timeout = setTimeout(async () => { + const tx_result = await axios.get(uri); + // Unicode for tx icon before tx_result data is printed + console.log("\u2705", tx_result.data); + clearInterval(timeout); + }, 1500); + } catch (e) { + console.log(e); + } // It should show up in unspent records as soon as program/execute resolves try { - const unspent_records = await axios.post( - "/api/testnet3/records/unspent", - { - view_key: account.viewKey().to_string(), - } - ); - console.log(unspent_records.data.records); - aleo_casino_table.records.push(...unspent_records.data.records); + const timeout = setTimeout(async () => { + const unspent_records = await axios.post( + "/api/testnet3/records/unspent", + { + view_key: account.viewKey().to_string(), + } + ); + // The keys are hashes, (field values) in string format + // Each record is JSON format of a serialized aleo_casino_table.aleo/CasinoTable.record + aleo_casino_table.consume(unspent_records.data.records); + clearInterval(timeout); + }, 1500); } catch (e) { console.log(e); } diff --git a/src/components/icons/IconInfo.vue b/src/components/icons/IconInfo.vue new file mode 100644 index 0000000..096a3dc --- /dev/null +++ b/src/components/icons/IconInfo.vue @@ -0,0 +1,16 @@ + diff --git a/src/stores/account.ts b/src/stores/account.ts index b533ec6..323ef66 100644 --- a/src/stores/account.ts +++ b/src/stores/account.ts @@ -42,7 +42,7 @@ const acc05 = computed(newAccount); const acc06 = computed(newAccount); const acc07 = computed(newAccount); -await pour(acc00.value.account); +// await pour(acc00.value.account); export const useAccountStore = defineStore("accounts", () => { return { diff --git a/src/stores/aleo_casino_table.ts b/src/stores/aleo_casino_table.ts index 1cf6c4e..8684922 100644 --- a/src/stores/aleo_casino_table.ts +++ b/src/stores/aleo_casino_table.ts @@ -1,4 +1,3 @@ -import { ref } from "vue"; import { defineStore } from "pinia"; // import { useWallet } from "@demox-labs/aleo-wallet-adapter-react"; @@ -12,22 +11,82 @@ export interface CasinoTable { export interface CasinoTableInfo { owner: string; - gates: number; + gates: bigint; seats: number; seats_occupied: number; seats_ready: number; dealer: string; player: string; + random_seed_hash: bigint; + random_seed: bigint; + _nonce: bigint; +} + +export interface RawCasinoTable { + owner: string; + gates: string; + seats: string; + seats_occupied: string; + seats_ready: string; + dealer: string; + player: string; random_seed_hash: string; - random_seed: number; + random_seed: string; + _nonce: string; } -export type CasinoTableList = CasinoTable[]; +export type RestResponse = { + [key: string]: string; +}; + +export type CasinoTableList = { + [key: string]: CasinoTableInfo; +}; + +export type txList = string[]; + +export const useCasinoTableStore = defineStore("CasinoTable", () => { + const records = {} as CasinoTableList; + const txIds = [] as txList; + + function parse_record(response: string): CasinoTableInfo { + const record_body = response + .replace(/ {2}/g, ' "') + .replace(/: /g, '": "') + .replace(/,/g, '",') + .replace(/\n}/g, '"\n}'); + const record: RawCasinoTable = JSON.parse(record_body); + return { + owner: record.owner.replace(".private", ""), + gates: BigInt(record.gates.replace("u64.private", "")), + seats: parseInt(record.seats.replace("u8.private", "")), + seats_occupied: parseInt(record.seats_occupied.replace("u8.private", "")), + seats_ready: parseInt(record.seats_ready.replace("u8.private", "")), + dealer: record.dealer.replace(".private", ""), + player: record.player.replace(".private", ""), + random_seed_hash: BigInt( + record.random_seed_hash.replace("field.private", "") + ), + random_seed: BigInt(record.random_seed.replace("u64.private", "")), + _nonce: BigInt(record._nonce.replace("group.public", "")), + }; + } -export const useCasinoTableStore = defineStore("casinoTable", () => { - const records = [] as CasinoTableList; + function consume(response: RestResponse): void { + const keys = Object.keys(response); + for (let i = 0; i < keys.length; i++) { + const key = keys[i]; + const record: CasinoTableInfo = parse_record(response[key]); + txIds.push(key); + records[key] = record; + // Unicode for record icon before printing record and key. + console.log("\u{1F4C8}", key, record); + } + } return { records, + txIds, + consume, }; }); diff --git a/src/views/DurakView.vue b/src/views/DurakView.vue index 95d2a1b..31595db 100644 --- a/src/views/DurakView.vue +++ b/src/views/DurakView.vue @@ -1,21 +1,27 @@