최근 MZ세대에 대한 미래 불확실성에 대해 많은 얘기가 오간다. MZ세대. 밀레니얼과 z 세대의 합성어로 x 세대와는 달리, 인터넷 기기 사용이나 모바일 서비스, 최신 트랜드등을 잘 이해하고 남들이 아닌 차별화된 내가 주체가 되는 성향을 보인 세대라고 표현한다.
하지만 이러한 MZ세대는 경제적 조건과 주어진 환경에 대해 상대적 박탈감을 많이 느끼기도 하는 세대이다. 여러 신조어 중 워라벨, 파이어족, 욜로족 등이 생겨버린 이유도 다른 사람이 아닌 내가 주체가 되어 나는 어떠한 삶을 살아가야 하는가에 대해 고민할 수밖에 없는 상황을 줬기 때문이라고 생각하고. 실제로 워라벨, 파이어족, 욜로족에 대한 관념을 100퍼센트 이해하고 그걸 따르는 사람이 있지만 그저 상황이 좋지 않기 때문에 자기합리화를 선택해 자신을 어떠한 개념에 종속시키려고 하는 사람도 있다. 이렇듯 MZ세대라는 이유가 아주 복잡한 경계선에 서 있고 어떠한 선택도 할 수 있으므로 많은 얘기가 오고 가는 것 같다.
MZ세대에 미래의 대한 불확실성에 대해 크게 두 가지 정도 추려보았다.
MZ세대의 수많은 키워드 중 경제적 여건과 관련된 가장 큰 키워드인 내 집 마련에 꿈, 그리고 낮은 임금 상승 폭을 주제로 답답한 현실에 조금이나마 위안을 얻을 수 있는 앱을 만들고자 "꿈자리와 관련된 로또 추출기 앱을 만들자고 생각했다."
실제로 지속되는 코로나와 낮은 고용, 임금 등의 여파로 인해 로또 판매량은 굉장히 높아졌다고 한다.
컨셉은 아주 간단하다. 어제 내가 꾼 꿈의 내용을 앱에 기록해 그 꿈과 관련된 로또 6개의 번호를 추출하는 앱이다.
개발환경
이 세 가지면 충분하고, 그다음으로 로직과 관련한 내용은
등이 있었다.
먼저 react-native 팀에서 제공하는 보일러 플레이트를 다운 받아보자.
npx react-native init [프로젝트 명]
그리고 package.json의 의존성 라이브러리 추가하자.
리엑트 네이티브의 네비게이션 스택을 쌓을 수 있도록 해주는 react-navigation 설치
npm install @react-navigation/native @react-navigation/native-stack react-native safe-area-context react-native-screens
서비스가 커진다면 부족한 구조이지만 로또 앱을 만들기에는 이 4가지면 충분하다.
맨 처음 해야하는 index.jsx 와 app.jsx 셋팅
app.js
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import MainNavigator from "./src/navigation/navigation";
const App = () => {
return (
<NavigationContainer >
<MainNavigator />
</NavigationContainer>
);
};
export default App;
그리고 네비게이션 셋팅
import * as React from 'react';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
//Screen
import { Splash } from "../screen/Splash";
import { Home } from "../screen/Home";
const defaultScreenOption = {
headerShown: false,
gestureEnabled: false
}
const Stack = createNativeStackNavigator();
const Navigation = () => {
return (
<Stack.Navigator screenOptions={defaultScreenOption}>
<Stack.Screen name="Splash" component={Splash}/>
<Stack.Screen name="Home" component={Home} />
</Stack.Navigator>
);
};
export default Navigation;
처음은 짤막하게 앱에 타이틀을 보여줄 수 있도록 Splash 화면을 보여줄수 있도록 구성하였고. 한 1초정도 지나면 바로 Home화면으로 넘어갈 수 있게 스택을 구성하였다.
그리고 앱에 대표 컬러를 변수로 활용하기 위해서 common/styles.jsx 를 생성.
const PASTEL_PUPPLE = "#D9D7F1";
const PASTEL_YELLOW = "#FFFDDE";
const PASTEL_GREEN = "#E7FBBE";
const PASTEL_PINK = "#FFCBCB";
export {
PASTEL_GREEN,
PASTEL_PINK,
PASTEL_YELLOW,
PASTEL_PUPPLE,
}
이 컬러는 미적 감각이 좋지않은 나를 위해 색상을 조합해주는 사이트에서 인기도가 높은 파스텔톤의 컬러를 채택하였다.
마지막으로 가장 중요한 로또를 생성하는 알고리즘을 가지고 있는 홈화면이다.
import React, { useState, useEffect } from "react";
import { SafeAreaView, View, Alert, Text, StyleSheet, TextInput, Button, BackHandler } from "react-native";
import { PASTEL_PUPPLE, PASTEL_YELLOW, PASTEL_PINK } from "../common/color";
import { Ball } from "../components/ball";
export const Home = () => {
const [ dream, setDream ] = useState("");
const [ flag, setFlag ] = useState(false);
const [ lotto, setLotto ] = useState([]);
const [ random, setRandom ] = useState([]);
const [ dataSum, setDateSum ] = useState(0);
const sortArray = (array) => {
return array.sort((a, b) => a - b);
}
const randomGenerateLotto = (length) => {
let randomArray = [];
for(let i = 0; i < length; i++) {
let tempArray = [];
for (let j = 0; j < 6; j++) {
tempArray.push(parseInt(String(Math.random() * 45 + 1)));
}
randomArray.push(setNumberGenerator(tempArray, dataSum));
}
return randomArray;
}
const setNumberGenerator = (array, sum) => {
const set = new Set([0]);
const tempArray = array.slice();
let count = 0;
while(count < 6) {
if (set.has((tempArray[count]) % 46 )) {
tempArray[count] += sum;
} else {
set.add((tempArray[count]) % 46);
tempArray[count] = (tempArray[count]) % 46;
count++;
}
}
return sortArray(tempArray);
}
const onGenerateLotto = () => {
const joinText = dream.split(" ").join("");
let randomArrays = [];
if(joinText.length <= 0) {
randomArrays = randomGenerateLotto(5);
setFlag(false);
setRandom(randomArrays);
} else {
randomArrays = randomGenerateLotto(4);
let total:number = 0;
let dreamArray = [];
for (let i = 0; i < dream.length; i++) {
total+= dream.charCodeAt(i);
}
for(let i = 2; i <= 7; i++) {
dreamArray.push(parseInt(String((total / i) * dataSum)));
}
dreamArray = setNumberGenerator(dreamArray, dataSum);
setLotto(dreamArray);
setRandom(randomArrays);
setFlag(true);
}
}
const backAction = () => {
Alert.alert("Hold on!", "앱을 종료하시겠습니까?", [
{
text: "취소",
onPress: () => null,
style: "cancel"
},
{ text: "확인", onPress: () => BackHandler.exitApp() }
]);
return true;
}
useEffect(() => {
BackHandler.addEventListener("hardwareBackPress", backAction)
return () => BackHandler.removeEventListener("hardwareBackPress", backAction);
}, [])
useEffect(() => {
const date = new Date();
let sum = 0;
sum += date.getFullYear();
sum += date.getMonth() + 1;
sum += date.getDate();
setDateSum(sum);
}, [])
return (
<SafeAreaView style={styles.background}>
<View style={styles.titleContainer}>
<Text style={styles.mainTitle}>
어떤 꿈을 꾸셨나요?
</Text>
<TextInput
style={styles.dreamInput}
onChangeText={setDream}
value={dream}
placeholder="자세할수록 확률이 올라갑니다."
/>
<Button
color={PASTEL_PUPPLE}
title="추출하기"
onPress={onGenerateLotto}
/>
{flag ?
<View>
<Text style={styles.lottoTitle}> 꿈자리 로또 번호</Text>
<View style={styles.dreamLotto}>
{lotto.map((number, index) => {
return <Ball key={index} number={number}/>
})}
</View>
<Text style={styles.lottoTitle} >랜덤 번호</Text>
<View style={styles.otherLottoList}>
{random.map((list, index)=> {
return (
<View key={index} style={styles.otherLotto}>
{[...list].map((number, index) => {
return <Ball key={index} number={number} />
})}
</View>
)
})}
</View>
</View>
:
<>
{random.length ? <Text style={styles.lottoTitle} >랜덤 번호</Text>: <></>}
<View style={styles.otherLottoList}>
{random.map((list, index)=> {
return (
<View key={index} style={styles.otherLotto}>
{[...list].map((number, index) => {
return <Ball key={index} number={number} />
})}
</View>
)
})}
</View>
</>
}
</View>
</SafeAreaView>
)
}
const styles = StyleSheet.create({
background: {
flex: 1,
},
mainTitle: {
fontSize: 25
},
titleContainer: {
flex: 1,
padding: 20,
},
dreamInput: {
borderColor: "black",
borderRadius:10,
borderWidth: 1,
margin: 10,
},
dreamLotto: {
backgroundColor: PASTEL_YELLOW,
flexDirection: "row",
alignItems:"center",
justifyContent:"center",
borderRadius: 20,
},
otherLottoList: {
backgroundColor: PASTEL_PINK,
borderRadius: 20,
},
otherLotto: {
flexDirection: "row",
alignItems:"center",
justifyContent:"center",
},
lottoTitle: {
fontSize:20,
margin:10,
}
})
함수는 3가지정도로 볼 수 있는데,
이다. 전체적으로 간략하게 설명하자면 인풋으로 들어온 텍스트를 아스키코드로 바꾸고 그 값을 날짜와 더해 1~45에 해당하는 겹치지않는 6개의 번호를 만드는 알고리즘이다.
재미있는 코딩을 통해 로또에 조금이나마 신앙심을 불어넣어 1등 당첨이 됐으면 하는 바람이다. 여기서 신앙심의 대상은 cpu이다. 내 cpu를 믿어보자.