Number Guessing Game tests wont pass despite passing in manual test

Tell us what’s happening:
Number guessing game works perfectly fine, tested it multiple times. All outputs are correct. I’ve tried using while loops, until loops, and objects like GUESS_LOOP() { } but everything fails the guessing game part of the tests.

As soon as the script enters the loop it fails every test associated with the guessing part of the script. If I delete the guessing loop, it will pass me on prompting for a username and taking input. If I add the loop, it will fail.

I do not understand how to pass these tests if the script isn’t supposed to finish unless it is canceled or the number is guessed.

Your code so far

#!/bin/bash

# Enter your username:
echo Enter your username:
read USER

# psql variable
PSQL="psql --username=freecodecamp --dbname=number_guess -t --no-align -c"

# rand number variable 1-1000
NUM=$((1 + $RANDOM % 1000))

# search user
USER_CHECK=$($PSQL "SELECT username FROM users WHERE username = '$USER'")

# if new, insert user and welcome "Welcome, USER! It looks like this is your first time here."
if [[ -z $USER_CHECK ]]
      then
      INSERT_USER=$($PSQL "INSERT INTO users(username) VALUES ('$USER')")
      echo "Welcome, $USER! It looks like this is your first time here."

# else welcome back and stats "Welcome back, USER! You have played games_played games, and your best game took best_game guesses."
      else
      USER_ID=$($PSQL "SELECT user_id FROM users WHERE username = '$USER'")
      USER_DATA=$($PSQL "SELECT COUNT(user_id), MIN(guesses) FROM games WHERE user_id = $USER_ID AND win = TRUE")
      echo "$USER_DATA" | while IFS="| && " read USER_GAMES USER_BEST
                          do
                          echo Welcome back, $USER_CHECK! You have played $USER_GAMES games, and your best game took $USER_BEST guesses.
                          done
fi

# new game
USER_ID=$($PSQL "SELECT user_id FROM users WHERE username = '$USER'")
NEW_GAME=$($PSQL "INSERT INTO games(user_id, guesses) VALUES ($USER_ID, 0)")

# prompt GUESS
echo -e "\nGuess the secret number between 1 and 1000:"

      until [[ $GUESS -eq $NUM ]]
      do

      read GUESS

            if [[ ! $GUESS =~ ^[0-9]+$ ]]
            then
            CURRENT_GAME=$($PSQL "SELECT MAX(game_id) FROM games")
            ATTEMPT=$($PSQL "UPDATE games SET guesses = guesses + 1 WHERE game_id = $CURRENT_GAME")
            echo "That is not an integer, guess again:"            

                  else
                        if [[ $GUESS -gt $NUM ]]
                        then
                        CURRENT_GAME=$($PSQL "SELECT MAX(game_id) FROM games")
                        ATTEMPT=$($PSQL "UPDATE games SET guesses = guesses + 1 WHERE game_id = $CURRENT_GAME")
                        echo "It's lower than that, guess again:"                        

                              else
                                    if [[ $GUESS -lt $NUM ]]
                                    then                                                      
                                    CURRENT_GAME=$($PSQL "SELECT MAX(game_id) FROM games")
                                    ATTEMPT=$($PSQL "UPDATE games SET guesses = guesses + 1 WHERE game_id = $CURRENT_GAME")
                                    echo "It's higher than that, guess again:"                                    
                                    fi
                        fi
            fi

      done
      CURRENT_GAME=$($PSQL "SELECT MAX(game_id) FROM games")
      ATTEMPT=$($PSQL "UPDATE games SET guesses = guesses + 1 WHERE game_id = $CURRENT_GAME")
      WINNER=$($PSQL "UPDATE games SET win = TRUE WHERE game_id = $CURRENT_GAME")
      TOTAL_GUESS_DATA=$($PSQL "SELECT guesses FROM games WHERE game_id = $CURRENT_GAME")
      echo "$TOTAL_GUESS_DATA" | while IFS="| && " read TOTAL_GUESSES
                                 do
                                 echo "You guessed it in $TOTAL_GUESSES tries. The secret number was $NUM. Nice job!"
                                 done

Here is a second loop I’ve tried…

#!/bin/bash

# psql variable
PSQL="psql --username=freecodecamp --dbname=number_guess -t --no-align -c"

# Enter your username
echo Enter your username:
read USER

# check for existing user
CHECK_USER=$($PSQL "SELECT username FROM users WHERE username = '$USER'")

# if exists get stats and welcome, elif create new user
if [[ -n $CHECK_USER ]]
then
      USER_ID=$($PSQL "SELECT user_id FROM users WHERE username = '$USER'")
      USER_GAMES=$($PSQL "SELECT COUNT(user_id) FROM games WHERE user_id = $USER_ID")
      USER_BEST=$($PSQL "SELECT MIN(guesses) FROM games WHERE user_id = $USER_ID")
      echo "Welcome back, $CHECK_USER! You have played $USER_GAMES games, and your best game took $USER_BEST guesses."
      
      elif [[ -z $CHECK_USER ]]
      then
            NEW_USER=$($PSQL "INSERT INTO users(username) VALUES ('$USER')")
            echo "Welcome, $USER! It looks like this is your first time here."
fi

# create rand number variable 1-1000 and prompt for guess
NUM=$((1 + $RANDOM % 1000))

echo Guess the secret number between 1 and 1000:
read GUESS

if [[ -n $GUESS ]]
then
      USER_ID=$($PSQL "SELECT user_id FROM users WHERE username = '$USER'")
      NEW_GAME=$($PSQL "INSERT INTO games(user_id, guesses) VALUES ($USER_ID, 0)")
fi

while [[ -n $GUESS ]]
do

if [[ $GUESS -eq $NUM ]]
then
break
fi

      while [[ ! $GUESS =~ ^[0-9]+$ ]]
      do
            CURRENT_GAME=$($PSQL "SELECT MAX(game_id) FROM games WHERE user_id = $USER_ID")
            ATTEMPT=$($PSQL "UPDATE games SET guesses = guesses + 1 WHERE game_id = $CURRENT_GAME")
            echo That is not an integer, guess again:
            read GUESS
      done

      if [[ $GUESS -gt $NUM ]]
      then
            CURRENT_GAME=$($PSQL "SELECT MAX(game_id) FROM games WHERE user_id = $USER_ID")
            ATTEMPT=$($PSQL "UPDATE games SET guesses = guesses + 1 WHERE game_id = $CURRENT_GAME")
            echo It\'s lower than that, guess again:
            read GUESS

            else
                  CURRENT_GAME=$($PSQL "SELECT MAX(game_id) FROM games WHERE user_id = $USER_ID")
                  ATTEMPT=$($PSQL "UPDATE games SET guesses = guesses + 1 WHERE game_id = $CURRENT_GAME")
                  echo It\'s higher than that, guess again:
                  read GUESS
      fi

done

CURRENT_GAME=$($PSQL "SELECT MAX(game_id) FROM games WHERE user_id = $USER_ID")
ATTEMPT=$($PSQL "UPDATE games SET guesses = guesses + 1 WHERE game_id = $CURRENT_GAME")
TOTAL_GUESSES=$($PSQL "SELECT guesses FROM games WHERE game_id = $CURRENT_GAME")
echo You guessed it in $TOTAL_GUESSES tries. The secret number was $NUM. Nice job!

And here is a dump of my database

--
-- PostgreSQL database dump
--

-- Dumped from database version 12.9 (Ubuntu 12.9-2.pgdg20.04+1)
-- Dumped by pg_dump version 12.9 (Ubuntu 12.9-2.pgdg20.04+1)

SET statement_timeout = 0;
SET lock_timeout = 0;
SET idle_in_transaction_session_timeout = 0;
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
SELECT pg_catalog.set_config('search_path', '', false);
SET check_function_bodies = false;
SET xmloption = content;
SET client_min_messages = warning;
SET row_security = off;

DROP DATABASE number_guess;
--
-- Name: number_guess; Type: DATABASE; Schema: -; Owner: freecodecamp
--

CREATE DATABASE number_guess WITH TEMPLATE = template0 ENCODING = 'UTF8' LC_COLLATE = 'C.UTF-8' LC_CTYPE = 'C.UTF-8';


ALTER DATABASE number_guess OWNER TO freecodecamp;

\connect number_guess

SET statement_timeout = 0;
SET lock_timeout = 0;
SET idle_in_transaction_session_timeout = 0;
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
SELECT pg_catalog.set_config('search_path', '', false);
SET check_function_bodies = false;
SET xmloption = content;
SET client_min_messages = warning;
SET row_security = off;

SET default_tablespace = '';

SET default_table_access_method = heap;

--
-- Name: games; Type: TABLE; Schema: public; Owner: freecodecamp
--

CREATE TABLE public.games (
    game_id integer NOT NULL,
    user_id integer NOT NULL,
    guesses integer,
    win boolean DEFAULT false NOT NULL
);


ALTER TABLE public.games OWNER TO freecodecamp;

--
-- Name: games_game_id_seq; Type: SEQUENCE; Schema: public; Owner: freecodecamp
--

CREATE SEQUENCE public.games_game_id_seq
    AS integer
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;


ALTER TABLE public.games_game_id_seq OWNER TO freecodecamp;

--
-- Name: games_game_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: freecodecamp
--

ALTER SEQUENCE public.games_game_id_seq OWNED BY public.games.game_id;


--
-- Name: users; Type: TABLE; Schema: public; Owner: freecodecamp
--

CREATE TABLE public.users (
    user_id integer NOT NULL,
    username character varying(20) NOT NULL
);


ALTER TABLE public.users OWNER TO freecodecamp;

--
-- Name: users_user_id_seq; Type: SEQUENCE; Schema: public; Owner: freecodecamp
--

CREATE SEQUENCE public.users_user_id_seq
    AS integer
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;


ALTER TABLE public.users_user_id_seq OWNER TO freecodecamp;

--
-- Name: users_user_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: freecodecamp
--

ALTER SEQUENCE public.users_user_id_seq OWNED BY public.users.user_id;


--
-- Name: games game_id; Type: DEFAULT; Schema: public; Owner: freecodecamp
--

ALTER TABLE ONLY public.games ALTER COLUMN game_id SET DEFAULT nextval('public.games_game_id_seq'::regclass);


--
-- Name: users user_id; Type: DEFAULT; Schema: public; Owner: freecodecamp
--

ALTER TABLE ONLY public.users ALTER COLUMN user_id SET DEFAULT nextval('public.users_user_id_seq'::regclass);


--
-- Data for Name: games; Type: TABLE DATA; Schema: public; Owner: freecodecamp
--

INSERT INTO public.games VALUES (247, 113, 153, false);
INSERT INTO public.games VALUES (246, 113, 77, false);
INSERT INTO public.games VALUES (249, 114, 291, false);
INSERT INTO public.games VALUES (251, 113, 441, false);
INSERT INTO public.games VALUES (252, 113, 492, false);
INSERT INTO public.games VALUES (248, 114, 228, false);
INSERT INTO public.games VALUES (250, 113, 372, false);


--
-- Data for Name: users; Type: TABLE DATA; Schema: public; Owner: freecodecamp
--

INSERT INTO public.users VALUES (113, 'user_1657208437724');
INSERT INTO public.users VALUES (114, 'user_1657208437723');


--
-- Name: games_game_id_seq; Type: SEQUENCE SET; Schema: public; Owner: freecodecamp
--

SELECT pg_catalog.setval('public.games_game_id_seq', 252, true);


--
-- Name: users_user_id_seq; Type: SEQUENCE SET; Schema: public; Owner: freecodecamp
--

SELECT pg_catalog.setval('public.users_user_id_seq', 114, true);


--
-- Name: games games_pkey; Type: CONSTRAINT; Schema: public; Owner: freecodecamp
--

ALTER TABLE ONLY public.games
    ADD CONSTRAINT games_pkey PRIMARY KEY (game_id);


--
-- Name: users users_pkey; Type: CONSTRAINT; Schema: public; Owner: freecodecamp
--

ALTER TABLE ONLY public.users
    ADD CONSTRAINT users_pkey PRIMARY KEY (user_id);


--
-- Name: games games_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: freecodecamp
--

ALTER TABLE ONLY public.games
    ADD CONSTRAINT games_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(user_id);


--
-- PostgreSQL database dump complete
--


Your browser information:

User Agent is: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36

Challenge: Build a Number Guessing Game

Link to the challenge:

Some issue might be what happens in that loop, consider whether updating number of guesses in the database is needed after every guess. What if somebody force quit program (Ctrl + C) during the game, the last attempt number would be potentially later taken as a best game result.

I changed the way it counts guesses but honestly I’m still confused as to why the tests aren’t passing. Now I have each guess counted in a separate table that is truncated at the start of each game, only updates to the main table if the number is guessed, and then truncates itself again.

ex: User guesses incorrectly, so…

UPDATE guess_counter SET guesses = guesses + 1 WHERE game_id = $CURRENT_GAME

It will continue to do this for each incorrect guess. If the number is guessed correctly it does this…

CURRENT_GAME=$($PSQL "SELECT MAX(game_id) FROM games WHERE user_id = $USER_ID")
ATTEMPT=$($PSQL "UPDATE guess_counter SET guesses = guesses +1 WHERE game_id = $CURRENT_GAME")
FINAL_GUESSES=$($PSQL "SELECT guesses FROM guess_counter WHERE game_id = $CURRENT_GAME")
INSERT_GUESSES=$($PSQL "UPDATE games SET guesses = $FINAL_GUESSES WHERE game_id = $CURRENT_GAME")
echo "You guessed it in $FINAL_GUESSES tries. The secret number was $NUM. Nice job!"
CLEAR_DATA=$($PSQL "TRUNCATE guess_counter")

Here is my current whole script:

#!/bin/bash

# psql variable
PSQL="psql --username=freecodecamp --dbname=number_guess -t --no-align -c"

# Enter your username
echo Enter your username:
read USER

# check for existing user
CHECK_USER=$($PSQL "SELECT username FROM users WHERE username = '$USER'")

# if exists get stats and welcome, elif create new user
if [[ -n $CHECK_USER ]]
then
      USER_ID=$($PSQL "SELECT user_id FROM users WHERE username = '$USER'")
      USER_GAMES=$($PSQL "SELECT COUNT(user_id) FROM games WHERE user_id = $USER_ID")
      USER_BEST=$($PSQL "SELECT MIN(guesses) FROM games WHERE user_id = $USER_ID")
      echo "Welcome back, $CHECK_USER! You have played $USER_GAMES games, and your best game took $USER_BEST guesses."
      
      elif [[ -z $CHECK_USER ]]
      then
            NEW_USER=$($PSQL "INSERT INTO users(username) VALUES ('$USER')")
            echo "Welcome, $USER! It looks like this is your first time here."
fi

# create rand number variable 1-1000 and prompt for guess
NUM=$((1 + $RANDOM % 1000))

echo Guess the secret number between 1 and 1000:
read GUESS

# create new game if guess is made
if [[ -n $GUESS ]]
then          
      USER_ID=$($PSQL "SELECT user_id FROM users WHERE username = '$USER'")
      NEW_GAME=$($PSQL "INSERT INTO games(user_id, guesses) VALUES ($USER_ID, 0)")
      ERASE_COUNTER=$($PSQL "TRUNCATE guess_counter")
	CURRENT_GAME=$($PSQL "SELECT MAX(game_id) FROM games WHERE user_id = $USER_ID")
      NEW_COUNT=$($PSQL "INSERT INTO guess_counter(game_id, guesses) VALUES ($CURRENT_GAME, 0)")
fi

# loop guesses until correct
while [[ $GUESS -ne $NUM ]]
do

      while [[ ! $GUESS =~ ^[0-9]+$ ]]
      do    
            ATTEMPT=$($PSQL "UPDATE guess_counter SET guesses = guesses +1 WHERE game_id = $CURRENT_GAME")             
            echo "That is not an integer, guess again:"
            read GUESS
      done
      
      if [[ $GUESS -gt $NUM ]]
      then        
            ATTEMPT=$($PSQL "UPDATE guess_counter SET guesses = guesses +1 WHERE game_id = $CURRENT_GAME")
            echo "It's lower than that, guess again:"
            read GUESS

            else   
                  ATTEMPT=$($PSQL "UPDATE guess_counter SET guesses = guesses +1 WHERE game_id = $CURRENT_GAME")               
                  echo "It's higher than that, guess again:"
                  read GUESS
      fi
      
done

# add final guess and congratulate
CURRENT_GAME=$($PSQL "SELECT MAX(game_id) FROM games WHERE user_id = $USER_ID")
ATTEMPT=$($PSQL "UPDATE guess_counter SET guesses = guesses +1 WHERE game_id = $CURRENT_GAME")
FINAL_GUESSES=$($PSQL "SELECT guesses FROM guess_counter WHERE game_id = $CURRENT_GAME")
INSERT_GUESSES=$($PSQL "UPDATE games SET guesses = $FINAL_GUESSES WHERE game_id = $CURRENT_GAME")
echo "You guessed it in $FINAL_GUESSES tries. The secret number was $NUM. Nice job!"
CLEAR_DATA=$($PSQL "TRUNCATE guess_counter")

I’m really confused and honestly quite frustrated. The script works. I don’t understand why tests 7-13 will not pass. If I delete my guessing loop, it recognizes test 7, sometimes it recognizes test 11, and most of the time none of them. When I check the database it looks like the script is just quitting because it logs 0 guesses.

I don’t know how to pass this when for all intents and purposes it functions as described in the tests, yet it will not pass.

I think @sanity is onto something here @dkenny17. Technically, your script works - but making a database query after each guess is quite inefficient. The tests make many guesses and can’t finish before they timeout. I think that’s what the problem is. I would try changing it to store the number of guesses for a game within the script’s memory and only write to the database once at the end of the game. Let us know if this works.

The tests could be more efficient as well - I will see if I can make some improvements to the tests and also maybe add something in the instructions to help users.

Here test asks to minimum 22 character while your dump creates VARCHAR(20)

-CREATE TABLE public.users (
user_id integer NOT NULL,
username character varying(20) NOT NULL
);