Squashed commit of the following:

commit efffda8fc2ae9ebf5df051c33159fc4334075470
Author: Trevor Welch <welch.trevor@yahoo.com>
Date:   Wed Apr 8 19:03:49 2020 -0400

    Fixed Reset Button

    Fingers crossed on last commit

commit ff6b739533c20e1eb3f4942b06def9fdfcf58548
Author: Trevor Welch <welch.trevor@yahoo.com>
Date:   Wed Apr 8 18:49:54 2020 -0400

    Copy Update + Radio Button Fix

    Changed the copy under "First-Time Buyer" and made the selected radio button a solid fill rather than only coloring the text.

commit 95887a68b671dcf231e4e7aea6710bfe4e2eae29
Author: Trevor Welch <welch.trevor@yahoo.com>
Date:   Wed Apr 8 18:31:18 2020 -0400

    Removed a Console Log

commit 84f1ef8b96730818903aaa0e12ab12be642f8bd1
Author: Trevor Welch <welch.trevor@yahoo.com>
Date:   Wed Apr 8 18:27:03 2020 -0400

    Added Probabilities

    Chart will now also display % chance of that pattern.

commit d047d7749ca2809165068fe3f787c83ffba8b45e
Author: Trevor Welch <welch.trevor@yahoo.com>
Date:   Wed Apr 8 18:08:35 2020 -0400

    Added "First Buy" and "Previous Pattern"

    All CSS needed for these fields have also been included, as well as some Javascript updated to reflect the new radios.

commit 95b60e1458df72c86cf91c2017cb8208e0829d9b
Merge: 1d6046b be09f8e
Author: Trevor Welch <welch.trevor@yahoo.com>
Date:   Wed Apr 8 13:51:53 2020 -0400

    Merge branch 'front-end'

commit be09f8e6085dccf90683c819a3deec44852a54b1
Author: Trevor Welch <welch.trevor@yahoo.com>
Date:   Wed Apr 8 13:51:43 2020 -0400

    Requested changes

    This commit adds changes as requested in https://github.com/mikebryant/ac-nh-turnip-prices/pull/34

commit 1d6046bfe283e6a779e2e2f49edd12b6fdf128bd
Author: Trevor Welch <welch.trevor@yahoo.com>
Date:   Wed Apr 8 02:34:12 2020 -0400

    typo

commit a414b8fdc22aaad82265d502601c0d2a67050f5d
Author: Trevor Welch <welch.trevor@yahoo.com>
Date:   Wed Apr 8 02:22:36 2020 -0400

    Update scripts.js

commit fbc3878d831e0f9abeb2de40337dedb8ee20f794
Merge: d521944 3cad0d4
Author: Trevor Welch <welch.trevor@yahoo.com>
Date:   Wed Apr 8 02:18:57 2020 -0400

    Merge branch 'master' of https://github.com/Trevor-Welch/ac-nh-turnip-prices

commit d521944eae82eeb0644b13ffa75a23ec3d2f52ef
Author: Trevor Welch <welch.trevor@yahoo.com>
Date:   Wed Apr 8 02:15:37 2020 -0400

    Massive UI Rework

    This commit completely changes the UI of the app, giving it a more Animal Crossing touch and make it feel like an app on the Nook Phone.

commit 3cad0d4f2a127ba46e946a9b0bebfc1cfb7001f2
Author: Trevor Welch <welch.trevor@yahoo.com>
Date:   Mon Apr 6 20:43:38 2020 -0400

    Refactored scripts.js

    Scripts.JS was very hard to read initially.

    This commity cleans things up, abstracts functions, and makes it a bit more easier to read.
master
Mike Bryant 4 years ago
parent f30e1e751e
commit 54b8458a5f

@ -1,20 +1,420 @@
#turnipTable th, #turnipTable td {
padding: 5px;
@import url('https://fonts.googleapis.com/css2?family=Raleway:wght@800&family=Varela+Round&display=swap');
/* - Global Styles - */
html {
font-size: 14px;
background: #DEF2D9;
background-image:
radial-gradient(#fff 20%, transparent 0),
radial-gradient(#fff 20%, transparent 0);
background-size: 30px 30px;
background-position: 0 0, 15px 15px;
/* background: #FFFAE5; */
}
body {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-family: 'Varela Round', sans-serif;
padding-bottom: 20vh;
}
h1 {
text-align: center;
font-size: 1.8rem;
}
h2 {
text-align: center;
font-size: 1.6rem;
}
.nook-phone {
width: 100%;
box-sizing: border-box;
margin: 16px auto;
border-radius: 40px;
padding: 16px 0px;
padding-bottom: 32px;
background: #F5F8FF;
color: #686868;
overflow: hidden;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06), 0 1px 2px rgba(0, 0, 0, 0.08);
}
.nook-phone-center {
background: white;
display: flex;
flex-direction: column;
align-items: center;
}
.dialog-box {
background: #FFFAE5;
box-sizing: border-box;
padding: 16px 24px;
margin: 32px auto;
position: relative;
border-radius: 40px;
max-width: 800px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06), 0 1px 2px rgba(0, 0, 0, 0.08);
}
.dialog-box p {
font-family: 'Raleway', sans-serif;
font-weight: 800;
font-size: 1.2rem;
color: #837865;
letter-spacing: 0.2px;
line-height: 1.8rem;
}
.dialog-box b,
.dialog-box a {
color: #0AB5CD;
transition: 0.2s all;
}
.dialog-box i {
font-style: normal;
color: #aaa;
}
.dialog-box a:hover {
color: #5ECEDB
}
.dialog-box .dialog-box__name {
position: absolute;
left: 16px;
top: -28px;
font-size: 1.1rem;
color: #BA3B1F;
padding: 4px 24px;
background: #FF9A40;
border-radius: 40px;
}
.input__form {
background: white;
display: flex;
flex-direction: column;
padding: 32px;
align-items: center;
}
.form__row {
display: flex;
flex-wrap: wrap;
margin-bottom: 32px;
justify-content: center;
align-items: center;
}
.form__row h6 {
width: 100%;
display: block;
font-weight: 800;
font-size: 1.5rem;
margin: 16px auto;
color: #845E44;
text-align: center;
}
.form__flex-wrap {
margin-top: 16px;
display: flex;
flex-wrap: wrap;
max-width: 100%;
justify-content: center;
}
.input__group {
display: flex;
flex-direction: column;
margin: 8px;
align-items: center;
}
.input__group label {
font-size: 1.2rem;
font-weight: bold;
margin-bottom: 8px;
opacity: 0.7;
text-align: center;
}
.form__flex-wrap .input__group label {
margin-left: 0px;
margin-bottom: 8px;
}
.input__form i {
text-align: center;
display: block;
font-style: normal;
color: #aaa;
font-size: 0.9rem;
margin: 8px auto;
}
.input__form>.form__row input {
margin: 0px auto;
}
input {
border: 0px solid white;
border-radius: 40px;
padding: 16px 24px;
font-size: 2rem;
font-family: inherit;
color: inherit;
font-weight: bold;
transition: 0.2s all;
margin: 8px 0px;
}
input[type=number]:placeholder-shown {
background: #f3f3f3;
}
input[type=number]:not(:placeholder-shown) {
background: transparent;
color: #0AB5CD;
}
input[type=number]:placeholder-shown:hover {
cursor: pointer;
transform: scale(1.1);
box-shadow: 0 1px 6px rgba(0, 0, 0, 0.05), 0 3px 6px rgba(0, 0, 0, 0.09);
}
input[type=number]:focus {
outline: none;
transform: scale(1.1);
background: white;
box-shadow: 0 1px 6px rgba(0, 0, 0, 0.05), 0 3px 6px rgba(0, 0, 0, 0.09);
}
input[type=number]:focus::placeholder {
opacity: 0;
}
input[type=number] {
width: 60px;
text-align: center;
}
input[type=number]:disabled {
background: inherit;
}
#turnipTable thead tr:first-child {
border: none;
input[type=number]:disabled:hover {
box-shadow: none;
transform: none;
cursor: default;
}
#turnipTable th {
text-align: center;
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
#turnipTable td:first-child {
white-space: nowrap;
text-align: left;
input[type=number] {
-moz-appearance: textfield;
}
.input__radio-buttons {
display: flex;
flex-wrap: wrap;
justify-content: center;
margin-top: 16px;
}
.input__radio-buttons input[type=radio] {
display: none;
}
.input__radio-buttons input[type="radio"]+label {
opacity: 1;
border: none;
border-radius: 40px;
background: #F3F3F3;
padding: 16px 24px;
font-size: 1.5rem;
font-family: inherit;
font-weight: bold;
transition: 0.2s all;
margin: 8px;
}
.input__radio-buttons input[type="radio"]:not(:checked)+label:hover {
cursor: pointer;
background: #F5F8FF;
transform: scale(1.1);
box-shadow: 0 1px 6px rgba(0, 0, 0, 0.05), 0 3px 6px rgba(0, 0, 0, 0.09);
}
.input__radio-buttons input[type="radio"]:checked+label {
background: #0AB5CD;
color: #FFF;
}
.reset-button {
font-family: inherit;
font-weight: bold;
color: #FFBABA;
padding: 8px 16px;
border-width: 0px;
border-radius: 40px;
background: transparent;
font-size: 1.2rem;
transition: 0.2s all;
position: relative;
margin: 32px auto;
}
.reset-button:hover {
transform: scale(1.1);
cursor: pointer;
opacity: 1;
box-shadow: 0 1px 6px rgba(0, 0, 0, 0.05), 0 3px 6px rgba(0, 0, 0, 0.09);
}
.table-wrapper {
display: inline-block;
max-width: 98%;
padding: 16px;
margin: 0px auto;
box-sizing: border-box;
overflow-x: auto;
border-radius: 2px;
}
.table-wrapper::-webkit-scrollbar {
height: 8px;
width: 5px;
}
.table-wrapper::-webkit-scrollbar-track {
height: 8px;
width: 5px;
box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.2);
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.2);
}
.table-wrapper::-webkit-scrollbar-thumb {
height: 8px;
width: 5px;
background: rgba(0, 0, 0, 0.2);
box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.2);
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1);
}
.table-wrapper::-webkit-scrollbar-thumb:window-inactive {
height: 8px;
width: 5px;
background: rgba(0, 0, 0, 0.2);
}
#turnipTable {
border-collapse: collapse;
}
#turnipTable th div:nth-of-type(1) {
margin-bottom: 2px;
}
#turnipTable th div:nth-of-type(2) {
display: flex;
justify-content: space-around;
opacity: 0.4;
}
#turnipTable td {
text-align: center;
max-width: 100px;
padding: 6px 4px;
text-align: center;
border-right: 1px solid rgba(0, 0, 0, 0.03);
border-bottom: 1px solid rgba(0, 0, 0, 0.15);
}
#turnipTable tbody tr {
opacity: 0.8;
}
#turnipTable tbody tr:hover {
cursor: default;
opacity: 1;
}
#turnipTable .table-pattern {
white-space: normal;
}
.waves {
position: relative;
width: 100%;
height: 5vh;
margin-bottom: -7px;
/*Fix for safari gap*/
max-height: 150px;
}
/* Animation */
.parallax>use {
animation: move-forever 25s cubic-bezier(.55, .5, .45, .5) infinite;
}
.parallax>use:nth-child(1) {
animation-delay: -2s;
animation-duration: 7s;
}
.parallax>use:nth-child(2) {
animation-delay: -3s;
animation-duration: 10s;
}
.parallax>use:nth-child(3) {
animation-delay: -4s;
animation-duration: 13s;
}
.parallax>use:nth-child(4) {
animation-delay: -5s;
animation-duration: 20s;
}
@keyframes move-forever {
0% {
transform: translate3d(-90px, 0, 0);
}
100% {
transform: translate3d(85px, 0, 0);
}
}
/*Shrinking for mobile*/
@media (max-width: 768px) {
.waves {
height: 40px;
min-height: 40px;
}
}

@ -1,22 +1,24 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Animal Crossing Turnip Price Forecaster</title>
<meta name="description" content="Animal Crossing Turnip Price Forecaster">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Animal Crossing - Turnip Prophet</title>
<meta name="description" content="Animal Crossing - Turnip Prophet">
<meta name="author" content="Mike Bryant">
<link rel="stylesheet" href="css/styles.css?v=1.0">
<!-- Compiled and minified CSS -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">
<link rel="stylesheet" href="css/styles.css">
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-162470902-1"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
function gtag() {
dataLayer.push(arguments);
}
gtag('js', new Date());
gtag('config', 'UA-162470902-1');
@ -24,196 +26,268 @@
</head>
<body>
<div class="container">
<div class="col s12 m5">
<div class="card-panel z-depth-0">
<span>
To use, enter as much data as you can from <b>your own island</b>. The tool will figure out all possible patterns and predict the lowest and highest prices for each day.
<p />
I couldn't have done this without <a href="https://twitter.com/_Ninji/status/1244818665851289602?s=20">Ninji's work extracting the code</a>
<p />
Support, comments and contributions are available through <a href="https://github.com/mikebryant/ac-nh-turnip-prices/issues">Github</a>
</span>
</div>
<div class="dialog-box">
<h2 class="dialog-box__name">Daisy Mae</h2>
<p>Hello, and welcome to the <b>Turnip Prophet</b> app on your Nook Phone.</p>
<p>This app let's you track your island's turnip prices daily, but you'll have to put the prices in yourself!
</p>
<p>After that, the Turnip Prophet app will <b>magically</b> predict the turnip prices you'll have for the rest of
the week.
</p>
</div>
<div class="nook-phone">
<h1>Turnip Prophet</h1>
<div>
<svg class="waves" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 24 150 28" preserveAspectRatio="none" shape-rendering="auto">
<defs>
<path id="gentle-wave" d="M-160 44c30 0 58-18 88-18s 58 18 88 18 58-18 88-18 58 18 88 18 v44h-352z" />
</defs>
<g class="parallax">
<use xlink:href="#gentle-wave" x="48" y="0" fill="rgba(255,255,255,0.6" />
<use xlink:href="#gentle-wave" x="48" y="3" fill="rgba(255,255,255,0.4)" />
<use xlink:href="#gentle-wave" x="48" y="5" fill="rgba(255,255,255,0.2)" />
<use xlink:href="#gentle-wave" x="48" y="7" fill="#fff" />
</g>
</svg>
</div>
<div class="row">
<div class="col s12">
<h5>Probability</h5>
<div class="row">
<div class="col s4">
<div class="input-field">
<select id="previous_pattern">
<option value="-1" selected>(unknown)</option>
<!-- Choices are ordered by increasing desirability, not code ID order -->
<option value="2">Decreasing</option>
<option value="0">Fluctuating</option>
<option value="3">Small spike</option>
<option value="1">Large spike</option>
</select>
<label for="previous_pattern">Last weeks pattern</label>
<div class="nook-phone-center">
<form class="input__form">
<div class="form__row">
<h6>First-Time Buyer</h6>
<div class="input__group">
<label>Is this your first time buying turnips from Daisy Mae on your island?<i>(This affects your
pattern)</i></label>
<div class="input__radio-buttons">
<input type="radio" id="first-time-radio-no" name="first-time" value="no" checked>
<label for="first-time-radio-no">No</label>
<input type="radio" id="first-time-radio-yes" name="first-time" value="yes">
<label for="first-time-radio-yes">Yes</label>
</div>
</div>
<div class="col s6">
<div class="input-field">
<span>
<b>Last weeks pattern</b> affects the probability of patterns for this week. If you know it, select it to see probabilities for this week. <em>(optional)</em>
</span>
</div>
<div class="form__row">
<h6>Previous Pattern</h6>
<div class="input__group">
<label for="">What was last week's turnip price pattern?<i>(This affects your pattern)</i></label>
<div class="input__radio-buttons">
<input type="radio" id="pattern-radio-unknown" name="pattern" value="unknown" checked>
<label for="pattern-radio-unknown">I don't know</label>
<input type="radio" id="pattern-radio-fluctuating" name="pattern" value="fluctuating">
<label for="pattern-radio-fluctuating">Fluctuating</label>
<input type="radio" id="pattern-radio-small-spike" name="pattern" value="small-spike">
<label for="pattern-radio-small-spike">Small Spike</label>
<input type="radio" id="pattern-radio-large-spike" name="pattern" value="large-spike">
<label for="pattern-radio-large-spike">Large Spike</label>
<input type="radio" id="pattern-radio-decreasing" name="pattern" value="decreasing">
<label for="pattern-radio-decreasing">Decreasing</label>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col s12">
<h5>Daisy Mae</h5>
<div class="row">
<div class="col s2">
<div class="input-field">
<label for="buy">Buy price</label>
<input type="number" id="buy">
<div class="form__row">
<h6>Sunday</h6>
<div class="input__group">
<label>What was the price of turnips this week? <i>(If this is your first time buying turnips, this field
will be disabled)</i></label>
<input type="number" id="buy" placeholder="..." />
</div>
</div>
<i>AM - 8:00 am to 11:59 am</i>
<i>PM - 12:00 pm to 10:00 pm</i>
<div class="form__flex-wrap">
<div class="form__row">
<h6>Monday</h6>
<div class="input__group">
<label for="sell_2">AM</label>
<input type="number" id="sell_2" placeholder="..." />
</div>
<div class="input__group">
<label for="sell_3">PM</label>
<input type="number" id="sell_3" placeholder="..." />
</div>
</div>
<div class="col s2">
<div class="input-field">
<label>
<input id="first_buy" type="checkbox" class="filled-in" />
<span>First time buyer</span>
</label>
<div class="form__row">
<h6>Tuesday</h6>
<div class="input__group">
<label for="sell_4">AM</label>
<input type="number" id="sell_4" placeholder="..." />
</div>
<div class="input__group">
<label for="sell_5">PM</label>
<input type="number" id="sell_5" placeholder="..." />
</div>
</div>
<div class="col s6">
<div class="input-field">
<span>
Check this box if you bought from Daisy on your own island <b>for the first time ever</b>. If you bought from her on your own island in a previous week, leave this box unchecked.
</span>
<div class="form__row">
<h6>Wednesday</h6>
<div class="input__group">
<label for="sell_6">AM</label>
<input type="number" id="sell_6" placeholder="..." />
</div>
<div class="input__group">
<label for="sell_7">PM</label>
<input type="number" id="sell_7" placeholder="..." />
</div>
</div>
<div class="form__row">
<h6>Thursday</h6>
<div class="input__group">
<label for="sell_8">AM</label>
<input type="number" id="sell_8" placeholder="..." />
</div>
<div class="input__group">
<label for="sell_9">PM</label>
<input type="number" id="sell_9" placeholder="..." />
</div>
</div>
<div class="form__row">
<h6>Friday</h6>
<div class="input__group">
<label for="sell_10">AM</label>
<input type="number" id="sell_10" placeholder="..." />
</div>
<div class="input__group">
<label for="sell_11">PM</label>
<input type="number" id="sell_11" placeholder="..." />
</div>
</div>
<div class="form__row">
<h6>Saturday</h6>
<div class="input__group">
<label for="sell_12">AM</label>
<input type="number" id="sell_12" placeholder="..." />
</div>
<div class="input__group">
<label for="sell_13">PM</label>
<input type="number" id="sell_13" placeholder="..." />
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col s2">
<h6>Monday</h6>
<div class="input-field col s6">
<label for="sell_2">AM</label>
<input type="number" id="sell_2">
</div>
<div class="input-field col s6">
<label for="sell_3">PM</label>
<input type="number" id="sell_3">
</div>
</div>
<div class="col s2">
<h6>Tuesday</h6>
<div class="input-field col s6">
<label for="sell_4">AM</label>
<input type="number" id="sell_4">
</div>
<div class="input-field col s6">
<label for="sell_5">PM</label>
<input type="number" id="sell_5">
</div>
</div>
<div class="col s2">
<h6>Wednesday</h6>
<div class="input-field col s6">
<label for="sell_6">AM</label>
<input type="number" id="sell_6">
</div>
<div class="input-field col s6">
<label for="sell_7">PM</label>
<input type="number" id="sell_7">
</div>
</div>
<div class="col s2">
<h6>Thursday</h6>
<div class="input-field col s6">
<label for="sell_8">AM</label>
<input type="number" id="sell_8">
</div>
<div class="input-field col s6">
<label for="sell_9">PM</label>
<input type="number" id="sell_9">
</div>
</div>
<div class="col s2">
<h6>Friday</h6>
<div class="input-field col s6">
<label for="sell_10">AM</label>
<input type="number" id="sell_10">
</div>
<div class="input-field col s6">
<label for="sell_11">PM</label>
<input type="number" id="sell_11">
</div>
</div>
<div class="col s2">
<h6>Saturday</h6>
<div class="input-field col s6">
<label for="sell_12">AM</label>
<input type="number" id="sell_12">
</div>
<div class="input-field col s6">
<label for="sell_13">PM</label>
<input type="number" id="sell_13">
</div>
</div>
</div>
<div class="row">
<div class="col s12">
<button id="reset" class="btn waves-effect waves-light" name="action">
Reset
<button id="reset" class="reset-button" name="action">
Reset Turnip Prophet
</button>
</div>
</div>
</form>
<div class="divider"></div>
<div class="card-panel z-depth-0">
<span>Your turnip prices will be one of the following patterns. Each cell contains the minimum..maximum price for that half-day. If you don't have a pattern, something's gone wrong, sorry &#128531;. Check back next week!</span>
<h2>Output</h2>
<div class="table-wrapper">
<table id="turnipTable">
<thead>
<tr>
<th valign="bottom">Pattern</th>
<th valign="bottom">% Chance</th>
<th valign="bottom">Sunday</th>
<th colspan="2">
<div>Monday</div>
<div>
<span>AM</span>
<span>PM</span>
</div>
</th>
<th colspan="2">
<div>Tuesday</div>
<div>
<span>AM</span>
<span>PM</span>
</div>
</th>
<th colspan="2">
<div>
<div>Wednesday</div>
<div>
<span>AM</span>
<span>PM</span>
</div>
</div>
</th>
<th colspan="2">
<div>Thursday</div>
<div>
<span>AM</span>
<span>PM</span>
</div>
</th>
<th colspan="2">
<div>Friday</div>
<div>
<span>AM</span>
<span>PM</span>
</div>
</th>
<th colspan="2">
<div>Saturday</div>
<div>
<span>AM</span>
<span>PM</span>
</div>
</th>
<th valign="bottom">Guaranteed Minimum</th>
<th valign="bottom">Potential Maximum</th>
</tr>
</thead>
<tbody id="output"></tbody>
</table>
</div>
</div>
<div class="section">
<table id="turnipTable" class="highlight">
<thead>
<tr>
<th rowspan="2">Pattern</th>
<th rowspan="2">% Chance</th>
<th rowspan="2">Sunday</th>
<th colspan="2">Monday</th>
<th colspan="2">Tuesday</th>
<th colspan="2">Wednesday</th>
<th colspan="2">Thursday</th>
<th colspan="2">Friday</th>
<th colspan="2">Saturday</th>
<th rowspan="2">Guaranteed Minimum</th>
<th rowspan="2">Potential Maximum</th>
</tr>
<tr>
<th>AM</th>
<th>PM</th>
<th>AM</th>
<th>PM</th>
<th>AM</th>
<th>PM</th>
<th>AM</th>
<th>PM</th>
<th>AM</th>
<th>PM</th>
<th>AM</th>
<th>PM</th>
</tr>
</thead>
<tbody id="output"></tbody>
</table>
<div style="transform:rotate(180deg)">
<svg class="waves" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 24 150 28" preserveAspectRatio="none" shape-rendering="auto">
<defs>
<path id="gentle-wave" d="M-160 44c30 0 58-18 88-18s 58 18 88 18 58-18 88-18 58 18 88 18 v44h-352z" />
</defs>
<g class="parallax">
<use xlink:href="#gentle-wave" x="48" y="0" fill="rgba(255,255,255,0.6" />
<use xlink:href="#gentle-wave" x="48" y="3" fill="rgba(255,255,255,0.4)" />
<use xlink:href="#gentle-wave" x="48" y="5" fill="rgba(255,255,255,0.2)" />
<use xlink:href="#gentle-wave" x="48" y="7" fill="#fff" />
</g>
</svg>
</div>
</div>
<div class="dialog-box">
<h2 class="dialog-box__name">Daisy Mae</h2>
<p>After you've listed some turnip prices, the Turnip Prophet will run some numbers and display the different
possible patterns that your island may experience.</p>
<p>This app is still in development, but will improve over time!</p>
</div>
<div class="dialog-box">
<h2 class="dialog-box__name">Daisy Mae</h2>
<p>
None of this would have been possible without <a
href="https://twitter.com/_Ninji/status/1244818665851289602?s=20">Ninji's work</a> figuring out just how Timmy
and Tommy value their turnips.
</p>
<p>
Support, comments and contributions are available through <a
href="https://github.com/mikebryant/ac-nh-turnip-prices/issues">Github</a>
</p>
</div>
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script src="js/predictions.js"></script>
<script src="js/scripts.js"></script>
<!-- Compiled and minified JavaScript -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
</body>
</html>

@ -48,17 +48,14 @@ function maximum_rate_from_given_and_base(given_price, buy_price) {
}
function* generate_pattern_0_with_lengths(given_prices, high_phase_1_len, dec_phase_1_len, high_phase_2_len, dec_phase_2_len, high_phase_3_len) {
/*
/*
// PATTERN 0: high, decreasing, high, decreasing, high
work = 2;
// high phase 1
for (int i = 0; i < hiPhaseLen1; i++)
{
sellPrices[work++] = intceil(randfloat(0.9, 1.4) * basePrice);
}
// decreasing phase 1
rate = randfloat(0.8, 0.6);
for (int i = 0; i < decPhaseLen1; i++)
@ -67,13 +64,11 @@ function* generate_pattern_0_with_lengths(given_prices, high_phase_1_len, dec_ph
rate -= 0.04;
rate -= randfloat(0, 0.06);
}
// high phase 2
for (int i = 0; i < (hiPhaseLen2and3 - hiPhaseLen3); i++)
{
sellPrices[work++] = intceil(randfloat(0.9, 1.4) * basePrice);
}
// decreasing phase 2
rate = randfloat(0.8, 0.6);
for (int i = 0; i < decPhaseLen2; i++)
@ -82,7 +77,6 @@ function* generate_pattern_0_with_lengths(given_prices, high_phase_1_len, dec_ph
rate -= 0.04;
rate -= randfloat(0, 0.06);
}
// high phase 3
for (int i = 0; i < hiPhaseLen3; i++)
{
@ -107,7 +101,7 @@ function* generate_pattern_0_with_lengths(given_prices, high_phase_1_len, dec_ph
min_pred = Math.floor(0.9 * buy_price);
max_pred = Math.ceil(1.4 * buy_price);
if (!isNaN(given_prices[i])) {
if (given_prices[i] < min_pred || given_prices[i] > max_pred ) {
if (given_prices[i] < min_pred || given_prices[i] > max_pred) {
// Given price is out of predicted range, so this is the wrong pattern
return;
}
@ -130,7 +124,7 @@ function* generate_pattern_0_with_lengths(given_prices, high_phase_1_len, dec_ph
if (!isNaN(given_prices[i])) {
if (given_prices[i] < min_pred || given_prices[i] > max_pred ) {
if (given_prices[i] < min_pred || given_prices[i] > max_pred) {
// Given price is out of predicted range, so this is the wrong pattern
return;
}
@ -154,7 +148,7 @@ function* generate_pattern_0_with_lengths(given_prices, high_phase_1_len, dec_ph
min_pred = Math.floor(0.9 * buy_price);
max_pred = Math.ceil(1.4 * buy_price);
if (!isNaN(given_prices[i])) {
if (given_prices[i] < min_pred || given_prices[i] > max_pred ) {
if (given_prices[i] < min_pred || given_prices[i] > max_pred) {
// Given price is out of predicted range, so this is the wrong pattern
return;
}
@ -177,7 +171,7 @@ function* generate_pattern_0_with_lengths(given_prices, high_phase_1_len, dec_ph
if (!isNaN(given_prices[i])) {
if (given_prices[i] < min_pred || given_prices[i] > max_pred ) {
if (given_prices[i] < min_pred || given_prices[i] > max_pred) {
// Given price is out of predicted range, so this is the wrong pattern
return;
}
@ -204,7 +198,7 @@ function* generate_pattern_0_with_lengths(given_prices, high_phase_1_len, dec_ph
min_pred = Math.floor(0.9 * buy_price);
max_pred = Math.ceil(1.4 * buy_price);
if (!isNaN(given_prices[i])) {
if (given_prices[i] < min_pred || given_prices[i] > max_pred ) {
if (given_prices[i] < min_pred || given_prices[i] > max_pred) {
// Given price is out of predicted range, so this is the wrong pattern
return;
}
@ -228,7 +222,6 @@ function* generate_pattern_0(given_prices) {
/*
decPhaseLen1 = randbool() ? 3 : 2;
decPhaseLen2 = 5 - decPhaseLen1;
hiPhaseLen1 = randint(0, 6);
hiPhaseLen2and3 = 7 - hiPhaseLen1;
hiPhaseLen3 = randint(0, hiPhaseLen2and3 - 1);
@ -285,7 +278,7 @@ function* generate_pattern_1_with_peak(given_prices, peak_start) {
if (!isNaN(given_prices[i])) {
if (given_prices[i] < min_pred || given_prices[i] > max_pred ) {
if (given_prices[i] < min_pred || given_prices[i] > max_pred) {
// Given price is out of predicted range, so this is the wrong pattern
return;
}
@ -312,7 +305,7 @@ function* generate_pattern_1_with_peak(given_prices, peak_start) {
max_pred = Math.ceil(max_randoms[i - peak_start] * buy_price);
if (!isNaN(given_prices[i])) {
if (given_prices[i] < min_pred || given_prices[i] > max_pred ) {
if (given_prices[i] < min_pred || given_prices[i] > max_pred) {
// Given price is out of predicted range, so this is the wrong pattern
return;
}
@ -373,7 +366,7 @@ function* generate_pattern_2(given_prices) {
if (!isNaN(given_prices[i])) {
if (given_prices[i] < min_pred || given_prices[i] > max_pred ) {
if (given_prices[i] < min_pred || given_prices[i] > max_pred) {
// Given price is out of predicted range, so this is the wrong pattern
return;
}
@ -403,7 +396,6 @@ function* generate_pattern_3_with_peak(given_prices, peak_start) {
/*
// PATTERN 3: decreasing, spike, decreasing
peakStart = randint(2, 9);
// decreasing phase before the peak
rate = randfloat(0.9, 0.4);
for (work = 2; work < peakStart; work++)
@ -412,14 +404,12 @@ function* generate_pattern_3_with_peak(given_prices, peak_start) {
rate -= 0.03;
rate -= randfloat(0, 0.02);
}
sellPrices[work++] = intceil(randfloat(0.9, 1.4) * (float)basePrice);
sellPrices[work++] = intceil(randfloat(0.9, 1.4) * basePrice);
rate = randfloat(1.4, 2.0);
sellPrices[work++] = intceil(randfloat(1.4, rate) * basePrice) - 1;
sellPrices[work++] = intceil(rate * basePrice);
sellPrices[work++] = intceil(randfloat(1.4, rate) * basePrice) - 1;
// decreasing phase after the peak
if (work < 14)
{
@ -454,7 +444,7 @@ function* generate_pattern_3_with_peak(given_prices, peak_start) {
if (!isNaN(given_prices[i])) {
if (given_prices[i] < min_pred || given_prices[i] > max_pred ) {
if (given_prices[i] < min_pred || given_prices[i] > max_pred) {
// Given price is out of predicted range, so this is the wrong pattern
return;
}
@ -475,11 +465,11 @@ function* generate_pattern_3_with_peak(given_prices, peak_start) {
// The peak
for (var i = peak_start; i < peak_start+2; i++) {
for (var i = peak_start; i < peak_start + 2; i++) {
min_pred = Math.floor(0.9 * buy_price);
max_pred = Math.ceil(1.4 * buy_price);
if (!isNaN(given_prices[i])) {
if (given_prices[i] < min_pred || given_prices[i] > max_pred ) {
if (given_prices[i] < min_pred || given_prices[i] > max_pred) {
// Given price is out of predicted range, so this is the wrong pattern
return;
}
@ -496,13 +486,13 @@ function* generate_pattern_3_with_peak(given_prices, peak_start) {
// Main spike 1
min_pred = Math.floor(1.4 * buy_price) - 1;
max_pred = Math.ceil(2.0 * buy_price) - 1;
if (!isNaN(given_prices[peak_start+2])) {
if (given_prices[peak_start+2] < min_pred || given_prices[peak_start+2] > max_pred ) {
if (!isNaN(given_prices[peak_start + 2])) {
if (given_prices[peak_start + 2] < min_pred || given_prices[peak_start + 2] > max_pred) {
// Given price is out of predicted range, so this is the wrong pattern
return;
}
min_pred = given_prices[peak_start+2];
max_pred = given_prices[peak_start+2];
min_pred = given_prices[peak_start + 2];
max_pred = given_prices[peak_start + 2];
}
predicted_prices.push({
min: min_pred,
@ -510,15 +500,15 @@ function* generate_pattern_3_with_peak(given_prices, peak_start) {
});
// Main spike 2
min_pred = predicted_prices[peak_start+2].min;
min_pred = predicted_prices[peak_start + 2].min;
max_pred = Math.ceil(2.0 * buy_price);
if (!isNaN(given_prices[peak_start+3])) {
if (given_prices[peak_start+3] < min_pred || given_prices[peak_start+3] > max_pred ) {
if (!isNaN(given_prices[peak_start + 3])) {
if (given_prices[peak_start + 3] < min_pred || given_prices[peak_start + 3] > max_pred) {
// Given price is out of predicted range, so this is the wrong pattern
return;
}
min_pred = given_prices[peak_start+3];
max_pred = given_prices[peak_start+3];
min_pred = given_prices[peak_start + 3];
max_pred = given_prices[peak_start + 3];
}
predicted_prices.push({
min: min_pred,
@ -527,31 +517,31 @@ function* generate_pattern_3_with_peak(given_prices, peak_start) {
// Main spike 3
min_pred = Math.floor(1.4 * buy_price) - 1;
max_pred = predicted_prices[peak_start+3].max - 1;
if (!isNaN(given_prices[peak_start+4])) {
if (given_prices[peak_start+4] < min_pred || given_prices[peak_start+4] > max_pred ) {
max_pred = predicted_prices[peak_start + 3].max - 1;
if (!isNaN(given_prices[peak_start + 4])) {
if (given_prices[peak_start + 4] < min_pred || given_prices[peak_start + 4] > max_pred) {
// Given price is out of predicted range, so this is the wrong pattern
return;
}
min_pred = given_prices[peak_start+4];
max_pred = given_prices[peak_start+4];
min_pred = given_prices[peak_start + 4];
max_pred = given_prices[peak_start + 4];
}
predicted_prices.push({
min: min_pred,
max: max_pred,
});
if (peak_start+5 < 14) {
if (peak_start + 5 < 14) {
var min_rate = 4000;
var max_rate = 9000;
for (var i = peak_start+5; i < 14; i++) {
for (var i = peak_start + 5; i < 14; i++) {
min_pred = Math.floor(min_rate * buy_price / 10000);
max_pred = Math.ceil(max_rate * buy_price / 10000);
if (!isNaN(given_prices[i])) {
if (given_prices[i] < min_pred || given_prices[i] > max_pred ) {
if (given_prices[i] < min_pred || given_prices[i] > max_pred) {
// Given price is out of predicted range, so this is the wrong pattern
return;
}
@ -660,7 +650,7 @@ function analyze_possibilities(sell_prices, first_buy, previous_pattern) {
weekMins.push(day.min);
weekMaxes.push(day.max);
}
poss.weekGuaranteedMinimum = Math.max(...weekMins);
poss.weekGuaranteedMinimum = Math.max(...weekMins);
poss.weekMax = Math.max(...weekMaxes);
}

@ -7,15 +7,41 @@ const getSellFields = function () {
return fields
}
const getFirstBuyRadios = function () {
return [
$("#first-time-radio-no")[0],
$("#first-time-radio-yes")[0]
];
}
const getPreviousPatternRadios = function () {
return [
$("#pattern-radio-unknown")[0],
$("#pattern-radio-fluctuating")[0],
$("#pattern-radio-small-spike")[0],
$("#pattern-radio-large-spike")[0],
$("#pattern-radio-decreasing")[0]
];
}
const getCheckedRadio = function (radio_array) {
return radio_array.find(radio => radio.checked === true).value
}
const checkRadioByValue = function (radio_array, value) {
radio_array.forEach(radio => radio.checked = false)
radio_array.find(radio => radio.value == value).checked = true
}
const sell_inputs = getSellFields()
const buy_input = $("#buy")
const first_buy_field = $("#first_buy");
const previous_pattern_input = $("#previous_pattern");
const first_buy_radios = getFirstBuyRadios()
const previous_pattern_radios = getPreviousPatternRadios()
//Functions
const fillFields = function (prices, first_buy, previous_pattern) {
first_buy_field.prop("checked", first_buy);
previous_pattern_input.val(previous_pattern);
first_buy == 'yes' ? checkRadioByValue(first_buy_radios, 'yes') : checkRadioByValue(first_buy_radios, 'no')
checkRadioByValue(previous_pattern_radios, previous_pattern);
buy_input.focus();
buy_input.val(prices[0] || '')
@ -50,9 +76,9 @@ const initialize = function () {
}
$("#reset").on("click", function () {
first_buy_field.prop('checked', false);
$("select").val(null);
$("input").val(null).trigger("input");
sell_inputs.forEach(input => input.value = '')
fillFields([], false, 'unknown')
update()
})
$('select').formSelect();
@ -75,11 +101,11 @@ const isEmpty = function (arr) {
}
const getFirstBuyState = function () {
return JSON.parse(localStorage.getItem('first_buy'))
return JSON.parse(localStorage.getItem('first_buy')) || 'no'
}
const getPreviousPatternState = function () {
return JSON.parse(localStorage.getItem('previous_pattern'))
return JSON.parse(localStorage.getItem('previous_pattern')) || 'unknown'
}
const getPricesFromLocalstorage = function () {
@ -130,37 +156,61 @@ const calculateOutput = function (data, first_buy, previous_pattern) {
}
let output_possibilities = "";
for (let poss of analyze_possibilities(data, first_buy, previous_pattern)) {
var out_line = "<tr><td>" + poss.pattern_description + "</td>"
var out_line = "<tr><td class='table-pattern'>" + poss.pattern_description + "</td>"
console.log(poss.probability)
out_line += `<td>${Number.isFinite(poss.probability) ? ((poss.probability * 100).toPrecision(3) + '%') : '—'}</td>`;
for (let day of poss.prices.slice(1)) {
if (day.min !== day.max) {
out_line += `<td>${day.min}..${day.max}</td>`;
out_line += `<td>${day.min} to ${day.max}</td>`;
} else {
out_line += `<td class="one">${day.min}</td>`;
out_line += `<td>${day.min}</td>`;
}
}
out_line += `<td class="one">${poss.weekGuaranteedMinimum}</td><td class="one">${poss.weekMax}</td></tr>`;
out_line += `<td>${poss.weekGuaranteedMinimum}</td><td>${poss.weekMax}</td></tr>`;
output_possibilities += out_line
}
$("#output").html(output_possibilities)
}
const convertPatternToInt = function (pattern) {
switch (pattern) {
case 'unknown':
return -1;
case 'fluctuating':
return 0;
case 'large-spike':
return 1;
case 'decreasing':
return 2;
case 'small-spike':
return 3;
default:
return -1;
}
}
const update = function () {
const sell_prices = getSellPrices();
const buy_price = parseInt(buy_input.val());
const first_buy = first_buy_field.is(":checked");
const previous_pattern = parseInt(previous_pattern_input.val());
const first_buy = getCheckedRadio(first_buy_radios);
const first_buy_boolean = first_buy == 'yes'
const previous_pattern = getCheckedRadio(previous_pattern_radios);
buy_input.prop('disabled', first_buy);
buy_input[0].disabled = first_buy_boolean;
buy_input[0].placeholder = first_buy_boolean ? '—' : '...'
const prices = [buy_price, buy_price, ...sell_prices];
if (!window.price_from_query) {
updateLocalStorage(prices, first_buy, previous_pattern);
}
calculateOutput(prices, first_buy, previous_pattern);
calculateOutput(prices, first_buy_boolean, parseInt(convertPatternToInt(previous_pattern)));
}
$(document).ready(initialize);
$(document).on("input", update);
$(previous_pattern_input).on("change", update);
$('input[type = radio]').on("change", update);

Loading…
Cancel
Save