State Management, Simplifying Some Components #1

Merged
innocuous-symmetry merged 8 commits from state-mgmt-backtrack into master 2022-07-24 19:14:17 +00:00
15 changed files with 441 additions and 256 deletions

View File

@@ -1,51 +1,21 @@
import { BrowserRouter, Routes, Route } from 'react-router-dom'
import { useState } from 'react' import { useState } from 'react'
import { BrowserRouter, Routes, Route } from 'react-router-dom'
import Gameboard from './components/Gameboard/Gameboard' import Gameboard from './components/Gameboard/Gameboard'
import GameConstructor from './util/GameConstructor'; import GameConstructor from './components/GameConstructor';
import { PlayerData, NobleData, CardData, AppState } from './util/types'; import { initialState } from './util/stateSetters';
import CardDeck from './data/cards.json';
import './App.css' import './App.css'
function App() { function App() {
const [state, setState] = useState<AppState>({ const [state, setState] = useState(initialState);
gameboard: {
nobles: new Array<NobleData>,
cardRows: {
tierOne: new Array<CardData>,
tierTwo: new Array<CardData>,
tierThree: new Array<CardData>,
},
tradingResources: {
ruby: 7,
sapphire: 7,
emerald: 7,
diamond: 7,
onyx: 7,
gold: 5
},
deck: CardDeck,
},
round: 1,
players: new Array<PlayerData>,
actions: {
getChips: {
active: false
},
buyCard: {
active: false
},
reserveCard: {
active: false
}
}
})
return ( return (
<div className="App"> <div className="App">
<h1>SPLENDOR</h1> <h1>SPLENDOR</h1>
<BrowserRouter> <BrowserRouter>
<Routes> <Routes>
{/* @ts-ignore */}
<Route path="/" element={<GameConstructor state={state} setState={setState} />} /> <Route path="/" element={<GameConstructor state={state} setState={setState} />} />
{/* @ts-ignore */}
<Route path="/game" element={<Gameboard state={state} setState={setState} />} /> <Route path="/game" element={<Gameboard state={state} setState={setState} />} />
</Routes> </Routes>
</BrowserRouter> </BrowserRouter>

View File

@@ -1,7 +1,6 @@
import { useEffect, useState } from "react" import { useEffect, useState } from "react"
import { useNavigate } from "react-router-dom" import { useNavigate } from "react-router-dom"
import { v4 } from "uuid"; import { CardData, NobleData, PlayerData, StateProps } from "../util/types";
import { CardData, NobleData, PlayerData, StateProps } from "./types";
interface InputState { interface InputState {
playerOne: PlayerInput playerOne: PlayerInput

View File

@@ -1,21 +1,71 @@
// types, data, utils
import { AppState, PlayerData, ResourceCost, SetActionType, StateProps } from '../../util/types';
import { setStateBuyCard, setStateGetChips, setStateReserveCard } from '../../util/stateSetters';
import { useCallback, useEffect, useState } from 'react'; import { useCallback, useEffect, useState } from 'react';
import { AppState, FullDeck, NobleData, StateProps } from '../../util/types';
import AllPlayers from '../Player/AllPlayers';
import AvailableChips from '../Resources/AvailableChips';
import CardRow from './CardRow';
import Nobles from './Nobles'; import Nobles from './Nobles';
import NobleStore from '../../data/nobles.json';
import useActionStatus from '../../util/useActionStatus'; // components
import initializeBoard from '../../util/initializeBoard';
import AvailableChips from '../Resources/AvailableChips';
import AllPlayers from '../Player/AllPlayers';
import CardRow from '../Card/CardRow';
import { validateChips } from '../Player/ActionMethods';
import SelectionView from '../Resources/SelectionView';
export default function Gameboard({ state, setState }: StateProps) { export default function Gameboard({ state, setState }: StateProps) {
const [view, setView] = useState(<p>Loading...</p>) const [view, setView] = useState(<p>Loading...</p>);
const [selection, setSelection] = useState<Array<String>>([]);
const chipSelection = { selection, setSelection };
// callbacks for lifting state
const liftSelection = useCallback((value: keyof ResourceCost) => {
if (!state.actions.getChips.active) return;
setState((prev: AppState) => {
let newSelection = prev.actions.getChips.selection;
newSelection?.push(value);
let newState = {
...prev,
actions: {
...state.actions,
getChips: {
active: true,
selection: newSelection,
valid: false
}
}
}
const result = validateChips(newState);
newState.actions.getChips.valid = result;
return newState;
})
}, [state]);
const setActionState = useCallback((value: SetActionType, player: PlayerData) => {
if (!player?.turnActive) return;
switch (value) {
case 0:
if (!state.actions.getChips.active) setState((prev) => setStateGetChips(prev));
break;
case 1:
if (!state.actions.buyCard.active) setState((prev) => setStateBuyCard(prev));
break;
case 2:
if (!state.actions.reserveCard.active) setState((prev) => setStateReserveCard(prev));
break;
default:
break;
}
}, []);
// util functions, setup on mount
useEffect(() => { useEffect(() => {
initializeBoard(); initializeBoard(state, setState);
}, []) }, [])
// displays state of board if data is populated
useEffect(() => { useEffect(() => {
if (!state.players.length) { if (!state.players.length) {
setView( setView(
@@ -32,61 +82,15 @@ export default function Gameboard({ state, setState }: StateProps) {
<CardRow tier={3} cards={state.gameboard.cardRows.tierThree} /> <CardRow tier={3} cards={state.gameboard.cardRows.tierThree} />
<CardRow tier={2} cards={state.gameboard.cardRows.tierTwo} /> <CardRow tier={2} cards={state.gameboard.cardRows.tierTwo} />
<CardRow tier={1} cards={state.gameboard.cardRows.tierOne} /> <CardRow tier={1} cards={state.gameboard.cardRows.tierOne} />
<AvailableChips liftFromChildren={liftFromChildren} chipSelection={chipSelection} state={state} setState={setState} /> <SelectionView state={state} setState={setState} />
<AllPlayers liftFromChildren={liftFromChildren} chipSelection={chipSelection} state={state} setState={setState} /> <AvailableChips state={state} setState={setState} liftSelection={liftSelection} />
{/* @ts-ignore */}
<AllPlayers state={state} setState={setState} setActionState={setActionState} />
</div> </div>
) )
} }
}, [state]); }, [state]);
const shuffleDeck = () => { // render
if (!state.gameboard.deck) return;
let newDeck: FullDeck = state.gameboard.deck;
for (const [key, value] of Object.entries(newDeck)) {
for (let i = value.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1))
const temp = value[i];
value[i] = value[j];
value[j] = temp;
}
}
setState({ ...state, gameboard: { ...state.gameboard, deck: newDeck }})
}
const setNobles = () => {
let newNobles = NobleStore.nobles;
let shuffledNobles = new Array<NobleData>;
while (shuffledNobles.length < 4) {
const rand = Math.floor(Math.random() * newNobles.length);
const randNoble = newNobles.splice(rand,1)[0];
shuffledNobles.push(randNoble);
}
setState({ ...state, gameboard: { ...state.gameboard, nobles: shuffledNobles }})
}
const initializeBoard = () => {
shuffleDeck();
let newDeck = state.gameboard.cardRows;
for (const [key, value] of Object.entries(state.gameboard.deck)) {
while (newDeck[key as keyof FullDeck].length < 4) {
// @ts-ignore
const nextCard = value.shift();
newDeck[key as keyof FullDeck].push(nextCard);
}
}
setState({ ...state, gameboard: { ...state.gameboard, cardRows: newDeck } })
setNobles();
}
const liftFromChildren = useCallback((childState: AppState) => {
setState(childState);
}, [state]);
return view return view
} }

View File

@@ -0,0 +1,103 @@
import { AppState, PlayerData, ResourceCost, setStateType } from "../../util/types";
import { turnOrderUtil } from "../../util/TurnOrderUtil";
import { initialActions } from "../../util/stateSetters";
export const _getChips = (resource: string | Array<keyof ResourceCost>, dynamic: PlayerData | undefined, setState: setStateType) => {
if (!dynamic || !dynamic?.turnActive) return;
setState((prev: AppState) => {
const { newPlayers, roundIncrement } = turnOrderUtil(prev, dynamic);
return {
...prev,
round: (roundIncrement ? prev.round + 1 : prev.round),
gameboard: {
...prev.gameboard,
tradingResources: {
...prev.gameboard.tradingResources,
[resource as keyof ResourceCost]: prev.gameboard.tradingResources[resource as keyof ResourceCost] -= 1
}
},
players: newPlayers
}
})
}
export const validateChips = (state: AppState): boolean => {
if (!state.actions.getChips.active || !state.actions.getChips.selection) return false;
const selection = state.actions.getChips.selection;
if (selection.length === 0 || selection.length > 3) return false;
const unique = new Set(selection);
if (selection.length === 3 && selection.length > unique.size) return false;
return true;
}
export const getChips = (state: AppState, setState: setStateType): boolean => {
/**
* features:
* update their inventory state
* update the total available resources
*/
let targetPlayer: PlayerData;
for (let each in state.players) {
if (state.players[each].turnActive) {
targetPlayer = state.players[each];
}
}
setState((prev) => {
const { newPlayers, roundIncrement } = turnOrderUtil(state, targetPlayer);
const idx = newPlayers.indexOf(targetPlayer);
const resources = state.actions.getChips.selection;
let newResources = prev.gameboard.tradingResources;
if (resources) {
for (let value of resources) {
// update player inventory
for (let each in newPlayers[idx].inventory) {
if (value === each) {
newPlayers[idx].inventory[value] += 1;
}
}
// update globally available resources
for (let each in newResources) {
if (value === each) {
newResources[value] -= 1;
}
}
}
}
return {
...prev,
round: (roundIncrement ? prev.round + 1 : prev.round),
gameboard: {
...prev.gameboard,
tradingResources: newResources
},
players: newPlayers,
actions: initialActions
}
})
console.log(state.players);
return true;
}
export const buyCard = () => {
return;
}
export const reserveCard = () => {
return;
}

View File

@@ -1,26 +1,17 @@
import Player from "./Player"; import Player from "./Player";
import { v4 } from "uuid"; import { v4 } from "uuid";
import { PlayerData, StateProps } from "../../util/types";
import { Dispatch, SetStateAction, useEffect } from "react";
import "./AllPlayers.css" import "./AllPlayers.css"
import { PlayerData, SetActionType, StateProps } from "../../util/types";
interface AllPlayersProps extends StateProps { interface AllPlayersProps extends StateProps {
liftFromChildren?: any, setActionState: (value: SetActionType, player?: PlayerData) => void
chipSelection: {
selection: String[],
setSelection: Dispatch<SetStateAction<Array<String>>>
}
} }
export default function AllPlayers({ state, setState, chipSelection, liftFromChildren }: AllPlayersProps) { export default function AllPlayers({ state, setState, setActionState }: AllPlayersProps) {
useEffect(() => {
return;
}, [state])
return ( return (
<div className="all-players"> <div className="all-players">
{ {
state.players?.map((player: PlayerData) => <Player key={v4()} liftFromChildren={liftFromChildren} chipSelection={chipSelection} player={player} state={state} setState={setState} />) state.players?.map((player: PlayerData) => <Player key={v4()} player={player} state={state} setState={setState} setActionState={setActionState} />)
} }
</div> </div>
) )

View File

@@ -1,85 +1,32 @@
import { AppState, ActionPrompts, GameActions, PlayerData, ResourceCost, StateProps } from "../../util/types"; import { PlayerData, SetActionType, StateProps } from "../../util/types"
import { Dispatch, SetStateAction, useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { TurnOrderUtil } from "../../util/TurnOrderUtil";
import useActionType from "../../util/useActionType";
import { v4 } from "uuid"; import { v4 } from "uuid";
interface PlayerProps extends StateProps { interface PlayerProps extends StateProps {
player: PlayerData player: PlayerData,
chipSelection: { setActionState: (value: SetActionType, player?: PlayerData) => void
selection: String[],
setSelection: Dispatch<SetStateAction<Array<String>>>
},
liftFromChildren: any
} }
export default function Player({ player, state, setState, chipSelection, liftFromChildren }: PlayerProps) { export default function Player({ player, state, setState, setActionState }: PlayerProps) {
const [actionPrompt, setActionPrompt] = useState(ActionPrompts[0]); const [dynamic, setDynamic] = useState<PlayerData>();
const [actionType, setActionType] = useState<GameActions>(GameActions.AWAIT); const [prompt, setPrompt] = useState("Your turn! Select an action type below.");
const [dynamic, setDynamic] = useState<PlayerData | undefined>(); const [actionSelection, setActionSelection] = useState(-1);
const { selection, setSelection } = chipSelection;
useEffect(() => setDynamic(state.players.find((element: PlayerData) => element.id === player.id)), [state]);
useEffect(() => { useEffect(() => {
return; setActionState(actionSelection, dynamic);
}, [selection, setSelection])
useEffect(() => { if (state.actions.getChips.active) {
setDynamic(state.players.find((element: PlayerData) => element.id === player.id)); setPrompt('Make your selection of up to three chips.');
}, [state, setState]); } else if (state.actions.buyCard.active) {
setPrompt('Choose a card above to purchase.');
useEffect(() => { } else if (state.actions.reserveCard.active) {
const newState = useActionType(state, actionType); setPrompt('Choose a card above to reserve.');
} else {
switch (actionType) { setPrompt("Your turn! Select an action type below.");
case GameActions.GETCHIPS:
setActionPrompt(ActionPrompts[1]);
getChips(newState);
setSelection([]);
break;
case GameActions.BUYCARD:
setActionPrompt(ActionPrompts[2]);
break;
case GameActions.RESERVECARD:
setActionPrompt(ActionPrompts[3]);
break;
default:
break;
} }
}, [actionType]); }, [actionSelection])
const getChips = (newState: AppState) => {
if (!dynamic?.turnActive) return;
setActionPrompt(ActionPrompts[1]);
if (selection.length < 3) return;
setState(() => {
const { newPlayers, roundIncrement } = TurnOrderUtil(newState, dynamic);
console.log(newPlayers)
let newResources = newState.gameboard.tradingResources;
for (let item of selection) {
for (let [key, value] of Object.entries(newResources)) {
if (key === item) {
newResources[key as keyof ResourceCost] = value - 1;
break;
}
}
}
return {
...newState,
round: (roundIncrement ? newState.round + 1 : newState.round),
players: newPlayers,
gameboard: {
...newState.gameboard,
tradingResources: newResources
},
}
})
liftFromChildren(state);
}
return ( return (
<div className="player-ui" key={v4()}> <div className="player-ui" key={v4()}>
@@ -89,11 +36,10 @@ export default function Player({ player, state, setState, chipSelection, liftFro
<p>Is {player.starter || "not"} round starter</p> <p>Is {player.starter || "not"} round starter</p>
{/* Dynamic data from state */} {/* Dynamic data from state */}
<p>{dynamic?.turnActive ? actionPrompt : "..."}</p> <p>{dynamic?.turnActive ? prompt : '...'}</p>
<button onClick={() => setActionSelection(0)}>Get Chips</button>
<button onClick={() => setActionType(GameActions.GETCHIPS)}>Get Chips</button> <button onClick={() => setActionSelection(1)}>Buy Card</button>
<button onClick={()=> setActionType(GameActions.BUYCARD)}>Buy a Card</button> <button onClick={() => setActionSelection(2)}>Reserve Card</button>
<button onClick={()=> setActionType(GameActions.RESERVECARD)}>Reserve a Card</button>
<div className="player-cards"></div> <div className="player-cards"></div>
<div className="player-resources"></div> <div className="player-resources"></div>
</div> </div>

View File

@@ -1,59 +1,31 @@
import { GameActions, ResourceCost, StateProps } from "../../util/types"; import { ResourceCost, StateProps } from "../../util/types";
import { useEffect } from "react";
import { v4 } from "uuid"; import { v4 } from "uuid";
import "./AvailableChips.css" import "./AvailableChips.css"
import { Dispatch, SetStateAction, useEffect, useState } from "react"; import { setStateGetChips } from "../../util/stateSetters";
import useActionStatus from "../../util/useActionStatus";
interface AvailableChipsProps extends StateProps { interface ResourceProps extends StateProps {
liftFromChildren: any, liftSelection: (value: keyof ResourceCost) => void
chipSelection: {
selection: String[],
setSelection: Dispatch<SetStateAction<Array<String>>>
}
} }
export default function AvailableChips({ state, chipSelection, liftFromChildren }: AvailableChipsProps) { export default function AvailableChips({ state, setState, liftSelection }: ResourceProps) {
const { selection, setSelection } = chipSelection;
const handleSelection = (key: string) => {
console.log(key)
console.log(state);
if (selection.length > 3) return;
setSelection((prev) => {
let newValue = prev;
newValue.push(key);
return newValue;
})
}
useEffect(() => { useEffect(() => {
useActionStatus(state); return;
}, [state]) }, [state])
return ( return (
<div className="available-chips"> <div className="available-chips">
<div className="current-selection">
<strong>Selection:</strong>
{ selection.map((each) => <p key={v4()}>{each}</p>) }
</div>
{ {
Object.keys(state.gameboard.tradingResources).map((key: string) => { Object.keys(state.gameboard.tradingResources).map((key: string | keyof ResourceCost) => {
return ( return (
<div key={v4()} className={`chips-${key}`}> <div key={v4()} className={`chips-${key}`}>
<button <button key={v4()} value={key} onClick={() => liftSelection(key as keyof ResourceCost)}>
onClick={() => handleSelection(key)}
value={key}>
{key}: {state.gameboard.tradingResources[key as keyof ResourceCost]} {key}: {state.gameboard.tradingResources[key as keyof ResourceCost]}
</button> </button>
</div> </div>
) )
}) })
} }
</div> </div>
) )
} }

View File

@@ -0,0 +1,38 @@
import { v4 } from "uuid";
import { useEffect, useState } from "react";
import { ResourceCost, StateProps } from "../../util/types";
import { setStateGetChips } from "../../util/stateSetters";
import { GetChipsHTML } from "./ViewHTML";
export default function SelectionView({ state, setState }: StateProps) {
const actionTypes = [
state.actions.getChips,
state.actions.buyCard,
state.actions.reserveCard
]
const [view, setView] = useState(<></>);
useEffect(() => {
setView(() => {
switch (true) {
case (actionTypes[0].active):
return <GetChipsHTML state={state} setState={setState} />
case (actionTypes[1].active):
return (
<>
{actionTypes[1].active && <strong>Your selection is {actionTypes[1].valid || "not"} valid</strong>}
<p>Card will display here</p>
</>
)
default:
return <></>;
}
})
}, [state])
return (
<div className="selection-view">
{ view }
</div>
)
}

View File

@@ -0,0 +1,36 @@
import { v4 } from "uuid";
import { useEffect, useState } from "react";
import { setStateGetChips } from "../../util/stateSetters";
import { ResourceCost, StateProps } from "../../util/types";
import { getChips } from "../Player/ActionMethods";
export const GetChipsHTML = ({ state, setState }: StateProps) => {
const [prompt, setPrompt] = useState("");
useEffect(() => {
if (!state.actions.getChips.active) setPrompt("");
if (state.actions.getChips.selection?.length === 0) {
setPrompt("Please make a selection.");
} else {
setPrompt(`Your selection is ${state.actions.getChips.valid ? '' : "not"} valid`);
}
}, [state])
return (
<div className="selection-view">
<strong>{prompt}</strong>
<div className="current-selections">
{
state.actions.getChips.active &&
state.actions.getChips.selection?.map((each: keyof ResourceCost) => <p key={v4()}>{each}</p>)
}
</div>
{
state.actions.getChips.valid ?
<button onClick={() => getChips(state, setState)}>Confirm Selection</button>
:
<button key={v4()} onClick={() => setState((prev) => setStateGetChips(prev))}>Reset Selection</button>
}
</div>
)
}

View File

@@ -1,10 +1,11 @@
import { AppState, PlayerData } from "./types"; import { AppState, PlayerData } from "./types";
export const TurnOrderUtil = (prev: AppState, dynamic: PlayerData) => { export const turnOrderUtil = (prev: AppState, dynamic: PlayerData) => {
let roundIncrement = false; let roundIncrement = false;
const newPlayers = prev.players; const newPlayers = prev.players;
for (let each of newPlayers) { for (let each of newPlayers) {
console.log(each);
if (each.id === dynamic.id) { if (each.id === dynamic.id) {
each.turnActive = false; each.turnActive = false;
} else if (each.id === dynamic.id + 1) { } else if (each.id === dynamic.id + 1) {

View File

@@ -0,0 +1,47 @@
import { AppState, FullDeck, NobleData, setStateType } from "./types";
import NobleStore from '../data/nobles.json';
const shuffleDeck = (state: AppState, setState: setStateType) => {
if (!state.gameboard.deck) return;
let newDeck: FullDeck = state.gameboard.deck;
for (const [key, value] of Object.entries(newDeck)) {
for (let i = value.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1))
const temp = value[i];
value[i] = value[j];
value[j] = temp;
}
}
setState({ ...state, gameboard: { ...state.gameboard, deck: newDeck }})
}
const setNobles = (state: AppState, setState: setStateType) => {
let newNobles = NobleStore.nobles;
let shuffledNobles = new Array<NobleData>;
while (shuffledNobles.length < 4) {
const rand = Math.floor(Math.random() * newNobles.length);
const randNoble = newNobles.splice(rand,1)[0];
shuffledNobles.push(randNoble);
}
setState({ ...state, gameboard: { ...state.gameboard, nobles: shuffledNobles }})
}
export default function initializeBoard(state: AppState, setState: setStateType) {
shuffleDeck(state, setState);
let newDeck = state.gameboard.cardRows;
for (const [key, value] of Object.entries(state.gameboard.deck)) {
while (newDeck[key as keyof FullDeck].length < 4) {
// @ts-ignore
const nextCard = value.shift();
newDeck[key as keyof FullDeck].push(nextCard);
}
}
setState({ ...state, gameboard: { ...state.gameboard, cardRows: newDeck } })
setNobles(state, setState);
}

79
src/util/stateSetters.ts Normal file
View File

@@ -0,0 +1,79 @@
import { AppState, CardData, NobleData, PlayerData, ResourceCost } from "./types";
import CardDeck from '../data/cards.json';
export const initialActions = {
buyCard: { active: false },
getChips: { active: false },
reserveCard: { active: false }
}
export const initialState = {
gameboard: {
nobles: new Array<NobleData>,
cardRows: {
tierOne: new Array<CardData>,
tierTwo: new Array<CardData>,
tierThree: new Array<CardData>,
},
tradingResources: {
ruby: 7,
sapphire: 7,
emerald: 7,
diamond: 7,
onyx: 7,
gold: 5
},
deck: CardDeck,
},
round: 1,
players: new Array<PlayerData>,
actions: initialActions
}
export const setStateAwaitAction = (prev: AppState) => {
return {
...prev,
actions: initialActions
}
}
export const setStateGetChips = (prev: AppState) => {
return {
...prev,
actions: {
...initialState.actions,
getChips: {
active: true,
selection: new Array<keyof ResourceCost>,
valid: false
}
}
}
}
export const setStateBuyCard = (prev: AppState) => {
return {
...prev,
actions: {
...initialState.actions,
buyCard: {
active: true,
valid: false
}
}
}
}
export const setStateReserveCard = (prev: AppState) => {
return {
...prev,
actions: {
...initialState.actions,
reserveCard: {
active: true,
includeGold: false,
valid: false
}
}
}
}

View File

@@ -13,45 +13,44 @@ export interface AppState {
}, },
round: number, round: number,
players: Array<PlayerData>, players: Array<PlayerData>,
actions: ActionTypes actions: StateActions
} }
export interface StateProps { interface StateActions {
state: AppState, setAction?: (arg: SetActionType) => void
setState: Dispatch<SetStateAction<AppState>> getChips: {
active: boolean
selection?: Array<keyof ResourceCost>
valid?: boolean
confirm?: () => void
}
buyCard: {
active: boolean
selection?: CardData
valid?: boolean
confirm?: () => void
}
reserveCard: {
active: boolean
selection?: CardData
includeGold?: boolean
valid?: boolean
confirm?: () => void
}
} }
export enum GameActions { export enum SetActionType {
GETCHIPS, GETCHIPS,
BUYCARD, BUYCARD,
RESERVECARD, RESERVECARD,
AWAIT AWAIT
} }
export interface ActionTypes { export type setStateType = Dispatch<SetStateAction<AppState>>
getChips: {
active: boolean
chips?: Array<keyof ResourceCost>
valid?: boolean
}
buyCard: {
active: boolean
card?: CardData | null
}
reserveCard: {
active: boolean
card?: CardData | null
includeGold?: boolean
}
}
export enum ActionPrompts { export interface StateProps {
"Choose your action type below:", state: AppState,
"Make a selection of three different available resources, or two of the same.", setState: setStateType
"Choose a card to purchase above.",
"Select any card above to reserve. You will also automatically take a gold chip.",
"Select any card above to reserve. You have the maximum allowed number of chips, so you cannnot take a gold chip.",
"It is not your turn."
} }
export interface GameInformation { export interface GameInformation {