Issue
Hello and Welcome!
INTRODUCTION
Thank you for viewing my question; each and every single one of your answer matters a ton to my journey towards the mastery of web development! I certainly very much appreciate all the support that the StackOverFlow community is providing to all junior developers who have just gone deep into the world of programming.
WHAT THE PROGRAM DOES
#-----------------------------------------------------------------------------
# Name: Lottery Simulator 2022
# Purpose: To encourage young people not to gamble on lotteries, as the probablity of correctly guessing the number is infinitemisial!
#
# Author: John Seong
# Created: 25-Feb-2022
# Updated: 01-Mar-2022
#-----------------------------------------------------------------------------
# I think this project deserves a level 4+ because...
#
# Features Added:
# Game being entirely web-based using the Flask micro web framework
# Utilization of both functional programming and object-oriented programming
# Calculate the chances of winning for the sake of learning why gambling is risky
# After a set of number is entered by the user, the combinations will reset and the program will give completely an arbitrary number set differing from the previous one
# The user can change the difficulty setting, which will determine the constraint of the possible number set
# Not only does it allow user to guess one number at a time, but multiple numbers stored in a dictionary
# In-game currency system that syncronizes with the SQLAlchemy database, which also generates the player leaderboard
# Game hosted on a cloud platform Heroku
# Used AJAX for communication between JAVASCRIPT and PYTHON files (via JSON)
#-----------------------------------------------------------------------------
PROBLEM I AM DEALING WITH
I got this error message on the console when I clicked the 'next' button three times which led to the ajax
method that aids the communication between the JAVASCRIPT and PYTHON files:
127.0.0.1 - - [04/Mar/2022 13:18:28] "POST /game HTTP/1.1" 400 -
HTML AND JAVASCRIPT
game.html
{% extends "index.html" %} {% block content %}
<head>
<script>
// TO DO: MAKE THE BAREBONE APP FIRST AND THEN PRETTIFY IT!
var counter = 0; // Button counter
var dict = {
'name': 0,
'range': 1,
'draws': 2
};
function onClickEvent() {
// Define all the elements by their ID...
const input = document.getElementById("name");
const warning = document.getElementById("warning");
const guide_text = document.getElementById("guide-text");
const guide_text_2 = document.getElementById("guide-text-2");
const array_renderer = document.getElementById("array-renderer");
const numbers_list = document.getElementById("numbers-list");
const name_of_input = document.getElementById("name").innerHTML;
const answers = []; // List for storing all the answers
// When no value is entered in the input, throw an error message...
if (document.forms['frm'].name.value === "") {
warning.style.display = 'block';
} else {
warning.style.display = 'none';
answers.push(document.forms['frm'].name.value);
counter++;
document.forms['frm'].name.value = "";
}
// Scene transition when the submit button is pressed once... twice... three times... etc.
if (counter == 1) {
guide_text.innerHTML = "SET THE<br>RANGE OF<br>POSSIBLE<br>NUMBERS";
guide_text_2.innerHTML = "DON'T GO TOO CRAZY!";
input.placeholder = "Enter min. and max. values seperated by a space...";
} else if (counter == 2) {
guide_text.innerHTML = "HOW MANY<br>DRAWS?";
guide_text_2.innerHTML = "IS MURPHY'S LAW REAL?";
input.placeholder = "Enter the number of draws...";
answers.push(document.forms['frm'].name.value);
} else if (counter == 3) {
$.ajax({
url: '{{ url_for("main.game") }}',
type: 'POST',
data: {
nickname: answers[dict['name']],
range: answers[dict['range']],
draws: answers[dict['draws']]
},
success: function(response) {
console.log("Successful attempt at retrieving the data!");
warning.style.display = 'none';
},
error: function(response) {
warning.style.display = 'block';
warning.innerHTML = "ERROR WHILE RETRIEVING THE LIST!"
}
});
guide_text.innerHTML = "GUESS THE<br>NUMBERS IN A<br>" + answers[dict['draws']] + " * 1 ARRAY!";
array_renderer.style.display = 'block';
// Parse the JSON file handed over by views.py (set that contains random numbers)
numbers_list.innerHTML = JSON.parse(data.random_set_json);
input.placeholder = "Enter the values seperated by a space...";
}
}
// Execute a function when the user releases a key on the keyboard => NEEDS FIX! DOESN'T WORK!
input.addEventListener("keyup", function(event) {
// Number 13 is the "Enter" key on the keyboard
if (event.keyCode === 13) {
// Cancel the default action, if needed
event.preventDefault();
// Trigger the button element with a click
document.getElementById("button").click();
}
});
</script>
<link rel="stylesheet" href="../static/bootstrap/css/style.css">
</head>
<header class="masthead" style="background: lightgray">
<div class="container h-100">
<div class="row h-100">
<div class="col-lg-7 my-auto" style="border-style: none;">
<div class="mx-auto header-content" style="background: rgba(47,37,48, 1);padding: 30px;border-radius: 34px; ;border-color: white;margin: 6px; color: white">
<h1 class="mb-5" id="guide-text" style="font-family: 'Roboto Mono', monospace;color: white;text-align: center;">WHAT IS<br>YOUR NAME?</h1>
<h3 id="guide-text-2" style="font-family: 'Roboto Mono', monospace; text-transform: uppercase; color: white">DON'T HESITATE! GO ON!</h3><br>
<form action="" name="frm" method="post">
<input class="form-control" type="text" id="name" name="name" placeholder="Enter your nickname...">
<br>
<div id="array-renderer">
<h3 id="numbers-list" style="font-family: 'Roboto Mono', monospace; text-transform: uppercase; color: white">NULL</h3><br>
</div>
<br><a class="btn btn-outline-warning btn-xl" role="button" id="button" onclick="onClickEvent()" href="#download" style="color: white;font-family: 'Roboto Mono', monospace;font-size: 20px; justify-self: center; align-self: center">Next</a>
<br><br>
<p id="warning" style="display: none; font-family: 'Roboto Mono', monospace; text-transform: uppercase; color: lightcoral">The value you entered is invalid. Please try it again.</p>
</form>
</div>
</div>
</div>
</div>
</header>
{% endblock content %}
PYTHON SCRIPT
views.py
from email.policy import default
from random import Random
from flask import Blueprint, render_template, request, session, jsonify
# from flask import current_app as app
import configparser
import json
from website.extensions import db
from .models import PlayerCurrency, RandomSet
# Import the config.cfg file and read the default value (starting point) of the game currency
config = configparser.ConfigParser()
# Get the absolute path of the CFG file by doing os.getcwd() and joining it to config.cfg
cfg_path = 'website/config.cfg'
bp = Blueprint('main', __name__)
# Whether user cookies will be collected or not
cookiesAvail = True
# Read the CFG file
config.read(cfg_path)
# Fix the 'failed to load' error!
try:
default_count = config.getint("default", "NUM_OF_NUMS")
default_coins = config.getint("default","MONEY")
except:
print('CFG file failed to load twice!')
@bp.route('/', methods=['GET', 'POST'])
def index():
if request.method == "POST":
allow_cookies = request.form.get("allow-cookies")
decline_cookies = request.form.get("decline-cookies")
session.clear()
if allow_cookies == 'allow' and decline_cookies != 'decline':
cookiesAvail = True
if decline_cookies == 'decline' and allow_cookies != 'allow':
cookiesAvail = False
return render_template("home.html")
@bp.route('/about')
def about():
session.clear()
return render_template("about.html")
@bp.route('/game', methods=['GET', 'POST'])
def game():
if request.method == 'POST':
# Clear the session
session.clear()
# Get all the user input values from game.js
player_name = json.loads(request.form['nickname'])
player_range = json.loads(request.form['range']).split(' ') # player_range[0] => min value, player_range[1] => max value
player_draws = json.loads(request.form['draws'])
# Define a random list object (instantiating a class located in models.py)
random_set = RandomSet(player_range[0], player_range[1], player_draws)
# Create a random list by generating arbitrary values
random_set.generate()
# Convert the generated random list (Python) into JSON-compatible string, so we can hand it over to game.js
random_set_json = json.dumps(random_set.current_set)
# INTERACTION BETWEEN JAVASCRIPT AND PYTHON (FLASK) USING AJAX AND JSONIFY: https://ayumitanaka13.medium.com/how-to-use-ajax-with-python-flask-729c0a8e5346
# HOW PYTHON-JSON CONVERSION WORKS USING THE JSON MODULE: https://www.w3schools.com/python/python_json.asp
return render_template("game.html")
# AJAX METHOD: https://ayumitanaka13.medium.com/how-to-use-ajax-with-python-flask-729c0a8e5346
# WHAT IS CURRENT_APP? LINK: https://flask.palletsprojects.com/en/2.0.x/appcontext/
# cd .. // go to the upper directory
# requirements.txt => # pip3 install -r requirements.txt to install the files
# COOKIES => WILL BE USED TO SKIP ENTER THE NAME STAGE IN SETUP!
# ADD DIFFICULY INDICATOR DEPENDING ON THE SCALE OF THE RANGE, AND SEPERATE THE LEADERBOARD BY DIFFICULTY LEVEL (EASY, MODERATE, HARD)
models.py
class RandomSet():
def __init__(self, min_value, max_value, draws):
self.min_value = min_value # Minimum value that the raodom number can be
self.max_value = max_value # Maximum value that the random numbers can be
self.count = draws # Number of draws
# A list that contains the set that computer generated, containing machine-picked arbitrary numbers
self.current_set = []
self.chances = 0 # Chances of winning, calculated by the computer
# Generate a set containing completely arbitrary numbers
def generate(self):
for i in range(self.count):
# Add a random value generated by a computer to the list using a for loop and a RANDINT built-in function
self.current_set.append(random.randint(
self.min_value, self.max_value))
# Calculate the chances and store it in the instance's variable
self.chances = calculate_chances(self.current_set, self.count)
def calculate_chances(current_set, count):
"""
Calculate the chances of winning,
by using the permuation formula
and converting it to a percentage.
"""
return str(f'{(1 / len(permutations(current_set, count))) * 100} %')
You can also check out the full code on my GitHub repository.
Solution
It turns out I had to double-JSON stringify the data that I was handing over to the server side.
So basically what it means is:
WHILE THE ORIGINAL CODE LOOKS LIKE THIS:
$.ajax({
url: '{{ url_for("main.game") }}',
type: 'POST',
data: {
nickname: answers[dict['name']],
range: answers[dict['range']],
draws: answers[dict['draws']]
},
THE CODE SHOULD LOOK LIKE THIS FOR IT TO WORK:
$.ajax({
url: '/game',
type: 'POST',
data: JSON.stringify({ // Make sure you surround the data variable(s) with JSON.stringify's MULTIPLE TIMES to avoid any potential error! Data HAS to be in JSON format.
nickname: JSON.stringify(answers[dict['name']]),
range: JSON.stringify(answers[dict['range']]),
draws: JSON.stringify(answers[dict['draws']])
}),
It was one simple mistake but took me an excruciatingly long time to catch.
Answered By - John Seong
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.