diff --git a/Gemfile b/Gemfile index 8017805..4d5e956 100644 --- a/Gemfile +++ b/Gemfile @@ -5,6 +5,7 @@ ruby "3.2.1" gem "sinatra" gem "sinatra-contrib" +gem "http" # Use Puma as the app server gem "puma", "~> 5.0" diff --git a/Gemfile.lock b/Gemfile.lock index fc6078a..8e17850 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -40,6 +40,7 @@ GEM rexml debug_inspector (1.1.0) diff-lcs (1.5.0) + domain_name (0.6.20240107) draft_matchers (0.0.2) capybara color_namer @@ -51,6 +52,10 @@ GEM ruby2_keywords (>= 0.0.4) faraday-net_http (3.0.2) faraday-retry (1.0.3) + ffi (1.16.3) + ffi-compiler (1.0.1) + ffi (>= 1.0.0) + rake grade_runner (0.0.9) activesupport (>= 2.3.5) faraday-retry (~> 1.0.3) @@ -58,8 +63,19 @@ GEM oj (~> 3.13.12) rake (~> 13) hashdiff (1.0.1) + http (5.1.1) + addressable (~> 2.8) + http-cookie (~> 1.0) + http-form_data (~> 2.2) + llhttp-ffi (~> 0.4.0) + http-cookie (1.0.5) + domain_name (~> 0.5) + http-form_data (2.3.0) i18n (1.12.0) concurrent-ruby (~> 1.0) + llhttp-ffi (0.4.0) + ffi-compiler (~> 1.0) + rake (~> 13.0) matrix (0.4.2) method_source (1.0.0) mini_mime (1.1.5) @@ -164,6 +180,7 @@ DEPENDENCIES capybara draft_matchers grade_runner + http i18n pry puma (~> 5.0) diff --git a/README.md b/README.md index a83f6f8..d65be20 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,66 @@ -# sinatra-template +# OMNICALC 4 -Use this repository to create new Sinatra apps. +This app is an extension of the OMNICALC lessons from previous modules. -Optionally, to use `ActiveRecord` for database operations, add to the `app.rb`: +It features: -```ruby -require "sinatra/activerecord" -``` +* Basic and scientific calculators + +* GPT Chat + +* Hangman and Tic-tac-toe games + +Note : +I wrote this app mostly to see the limitations and strengths of the Ruby language. +It still needs work in a couple of areas : + + * Some of the code should be refactored. + + * Maybe use a different font, so that the images in the games line up better. + +I hope you have as much fun with this app as I had writing it. + +# How to use the app : + +Basic calculator : +------------------ + +You should be able to use this calculator like a normal calculator. + +Scientific calculator : +----------------------- + +This can also be used as a normal calculator with an exception: +The higher-math functions( exponent, factorial ) calls functions from mathjs api. + +Here's the documentation : +https://mathjs.org/docs/reference/functions.html + +Chat GPT : +---------- + +* Ask a question in the text box below the controls and click "SEND". + +* Use the up and down arrows to scroll through the answer. + +Games ( Hangman ) : +------------------- + +* Click on the letter that you want to guess. + +* If the guess is incorrect, a portion of the man will be drawn, if the man is completely drawn, then the game is over. + +* If you correctly guess the word, then you win and the game is over. + +* Click the "RESET" button for a new game. + +Games ( Tic-tac-toe ) : +----------------------- + +* Click any of the yellow buttons below the display, corresponding to the position on the board that you would like to draw your 'X'. + +* The computer will automatically move. + +* Clicking "RESET" will also reset this game. -And in the `config/environment.rb` file add this code block: -```ruby -configure do - # setup a database connection - set(:database, { adapter: "sqlite3", database: "db/development.sqlite3" }) -end -``` diff --git a/app.rb b/app.rb index abbd1c7..2f0bcec 100644 --- a/app.rb +++ b/app.rb @@ -1,9 +1,442 @@ require "sinatra" require "sinatra/reloader" +require "http" +require "json" +require "uri" +require "./libraries/calculator.rb" +require "./libraries/display.rb" +require "./libraries/games.rb" + +MATH_API = "http://api.mathjs.org/v4/?expr=" + +display_size = 12 +lower_display_range = 0 +upper_display_range = 7 + +@display_array = Array.new(display_size) + +@calculator_mode = "basic" + +calc_display = Display.new +calc_object = Calculator.new +calc_tictactoe = Tic_tac_toe.new +calc_hangman = Hangman.new + +calc_start = true + +#======================================================== + +#Test tic-tac-toe grid +game_choice = "tic-tac-toe" +calc_tictactoe.reset_game +calc_tictactoe.render_game_board + + +#======================================================== +#======================================================== get("/") do - " -
Define some routes in app.rb
- " + + # We do this only once, to welcome the user : + + calc_display.add_to_history("Welcome to OMNICALC4 !!") + calc_display.add_to_history("Have fun !!") + + redirect("/basic") + +end + +#======================================================== + +get("/process_calc/:input_data") do + + input_data = params.fetch("input_data") + + input_array = input_data.split(":") + + calc_input = " " + + calc_input = input_array[0] + calc_mode = input_array[1] + +#------------------------------------------------- +# We will be defining out input processing here : + + case calc_input + + # Basic : + + when "DIV" + calc_input = "/" + + when "MUL" + calc_input = "*" + + when "ADD" + calc_input = "+" + + when "SUB" + calc_input = "-" + + when "PERCENT" + calc_input = "%" + + when "DEC" + calc_input = "." + + # Math functions : + + when "POW" + calc_input = "pow(" + + when "SQR" + calc_input = "sqrt(" + + when "NTHRT" + calc_input = "nthRoots(" + + when "LOG" + calc_input = "log(" + + when "TENPOW" + calc_input = "pow(10," + + when "NEGTENPOW" + calc_input = "pow(10,-" + + when "SIN" + calc_input = "sin(" + + when "COS" + calc_input = "cos(" + + when "TAN" + calc_input = "tan(" + + when "INVSIN" + calc_input = "asin(" + + when "INVCOS" + calc_input = "acos(" + + when "INVTAN" + calc_input = "atan(" + + when "RECIP" + calc_input = "1/" + + when "FACTOR" + calc_input = "factorial(" + + when "MOD" + calc_input = "mod(" + + # GPT + when "UP" + calc_input = "" + + if lower_display_range > 0 + lower_display_range -= 1 + upper_display_range -= 1 + end + + + + when "DOWN" + calc_input = "" + + if upper_display_range < calc_display.get_history_size-1 + lower_display_range += 1 + upper_display_range += 1 + end + + + + # Constants : + when "E" + calc_input = "2.718" + + when "PI" + calc_input = "3.141" + + + # "Auxilliary" buttons : + + when "CLEAR" + calc_display.add_to_history(" ") + calc_input = "" + + when "AC" + calc_display.reset_display + calc_input = "" + + + # Non-numeric characters : + + when "OPENPAREN" + calc_input = "(" + + when "CLOSEPAREN" + calc_input = ")" + + when "COMMA" + calc_input = "," + +#---------------------------------------------------- + + when "EQU" + + expression = calc_display.history_line(upper_display_range) + output = calc_object.calculate(expression) + calc_display.add_to_history(output) + calc_input = "" + + end + +#---------------------------------------------- + if calc_start + calc_display.add_to_history(calc_input) + calc_start = false + + else + calc_display.set_display(upper_display_range, calc_input) + + end + +#---------------------------------------------- + + case calc_mode + + when "BAS" + redirect("/basic") + + when "SCI" + redirect("/scientific") + + when "GPT" + redirect("/gpt") + + end + +end + +#======================================================== + +post("/get_response") do + + gpt_message = params.fetch("gpt_message") + + calc_display.reset_display + + open_ai_api_key = ENV.fetch("OPEN_AI_KEY") + + request_headers_hash = { + "Authorization" => "Bearer #{open_ai_api_key}", + "content-type" => "application/json" + } + + request_body_hash = { + "model" => "gpt-3.5-turbo", + "messages" => [ + { + "role" => "user", + "content" => "#{gpt_message}" + } + ] + } + + request_body_json = JSON.generate(request_body_hash) + + raw_response = HTTP.headers(request_headers_hash).post( + "https://api.openai.com/v1/chat/completions", + :body => request_body_json + ).to_s + + parsed_response = JSON.parse(raw_response, object_class: OpenStruct) + + gpt_response = parsed_response.choices[0].message.content + + # Format and adjust the response on the screen so that it can be + # read by the user. + + calc_display.format_and_display(gpt_response) + + lower_display_range = 0 + + upper_display_range = display_size-1 + + redirect("/gpt") + +end + + +#======================================================== + +get("/basic") do + + upper_display_range = calc_display.get_history_size - 1 + lower_display_range = upper_display_range - display_size + + @calculator_mode = "basic" + + @display_array = calc_display.window(lower_display_range, upper_display_range) + + erb(:basic_calculator) + +end + +#======================================================== + + +get("/scientific") do + + upper_display_range = calc_display.get_history_size - 1 + lower_display_range = upper_display_range - display_size + + @calculator_mode = "scientific" + + @display_array = calc_display.window(lower_display_range, upper_display_range) + + erb(:sci_calculator) + +end + + +#======================================================== + +get("/gpt") do + + @display_array = calc_display.window(lower_display_range, display_size) + + @calculator_mode = "gpt" + + erb(:gpt_calculator) + +end + + +#======================================================== + +get("/games") do + + calc_display.reset_display + + if game_choice == "tic-tac-toe" + + + game_display = calc_tictactoe.render_game_board + + game_state_string = calc_tictactoe.get_game_state + + if game_state_string != "no_wins" + calc_tictactoe.print_message(20, 4, game_state_string) + end + + line_count = 0 + + game_display.each do |display_line| + + calc_display.set_display(line_count, display_line) + line_count += 1 + + end +#.................................... + elsif game_choice == "hangman" + + line_count = 0 + + game_display = calc_hangman.update_screen + + won_or_lost = calc_hangman.win_or_lose + + game_display.each do |display_line| + + calc_display.set_display(line_count, display_line) + line_count += 1 + + end + + end # Of condition block for hangman +#.................................... + + @calculator_mode = "games" + + @display_array = calc_display.window(0, display_size) + + @game_selected = game_choice + + erb(:games_calculator) + +end + +#======================================================== + +get("/reset_game") do + + calc_display.reset_display + + if game_choice == "tic-tac-toe" + + calc_tictactoe.reset_game + calc_tictactoe.render_game_board + + elsif game_choice == "hangman" + + calc_hangman.reset_game + + end + + redirect("/games") + +end + +#======================================================== + +get ("/change_game/:game") do + + calc_display.reset_display + + game_choice = params.fetch("game") + + redirect("/reset_game") + +end + +#======================================================== + +get("/process_move/:row/:column") do + + row = params.fetch("row") + column = params.fetch("column") + + if calc_tictactoe.game_done == "no" + + calc_tictactoe.player_move(row.to_i, column.to_i) + calc_tictactoe.get_game_state + + end + + + if calc_tictactoe.game_done == "no" + + calc_tictactoe.computer_move + calc_tictactoe.get_game_state + + end + + + redirect("/games") + +end + +#======================================================== + +get("/process_choice/:picked_letter") do + + picked_letter = params.fetch("picked_letter") + + calc_hangman.check_picked_letter(picked_letter) + + redirect("/games") + end diff --git a/libraries/calculator.rb b/libraries/calculator.rb new file mode 100644 index 0000000..c851d82 --- /dev/null +++ b/libraries/calculator.rb @@ -0,0 +1,46 @@ +class Calculator + + def initialize + @running_amount = "" + @MATH_API = "http://api.mathjs.org/v4/?expr=" + @parenthesis_status = "CLOSED" + + end # Of method + +#--------------------------------- + + def calculate(expression, precision_setting = 0) + + url_encoded_expression = CGI.escapeURIComponent(expression) + + calculate_url = @MATH_API + url_encoded_expression + + result = HTTP.get(calculate_url).to_s + + @running_amount = result + + result + + end # Of method + +#--------------------------------- + +def get_running_amount() + + @running_amount.to_s + +end + + #--------------------------------- + + def reset_running_amount() + + @running_amount = 0 + @running_amount.to_s + + end + +#--------------------------------- + + +end # Of class diff --git a/libraries/display.rb b/libraries/display.rb new file mode 100644 index 0000000..7b56367 --- /dev/null +++ b/libraries/display.rb @@ -0,0 +1,117 @@ +class Display + + def initialize + # We are going to hardcode some things here : + @history_size = 40 + @ultimate_line_length = 38 + + @display_history = Array.new(@history_size, " ") + + + end + + #------------------------------- + + def window(lower_range, number_of_lines) + + @display_history.slice(lower_range, number_of_lines) + + end + + #------------------------------- + + def set_display(location, display_output, new_line = false) + + if location > @history_size-1 + location = @history_size-1 + end + + if !new_line + @display_history[location] += display_output + + else + @display_history[location] = display_output + end + + end + + #------------------------------- + + def history_line(line_number) + + if line_number >= @history_size + @display_history[@history_size-1] + else + @display_history[line_number] + end + + end + + #------------------------------- + + + def add_to_history(message_string) + + history_counter = 0 + + while history_counter < @history_size do + + temporary_string = @display_history[history_counter+1] + @display_history[history_counter] = temporary_string + history_counter += 1 + + end + + @display_history[history_counter-1] = message_string + + end + + #------------------------------- + + def reset_display() + + end_of_array = @display_history.length()-1 + + for counter in 0..end_of_array + + @display_history[counter] = " " + + end + + end + + #------------------------------- + + def format_and_display(string_to_format) + + line_count = 0 + + while string_to_format.length > @ultimate_line_length do + + temp_string = string_to_format.slice(0, @ultimate_line_length) + + temp_string = temp_string.gsub("\n"," ") + + self.set_display(line_count, temp_string) + + string_to_format = string_to_format.slice(@ultimate_line_length, string_to_format.length) + + line_count += 1 + + end + + self.set_display(line_count, string_to_format) + + line_count + + end + + #------------------------------- + + def get_history_size() + + @history_size + + end + +end # Of class diff --git a/libraries/games.rb b/libraries/games.rb new file mode 100644 index 0000000..33fe0fd --- /dev/null +++ b/libraries/games.rb @@ -0,0 +1,512 @@ +# For Hangman : generate random word : +# https://random-word-api.vercel.app/api?words=1 + +class Games + + def initialize + + @max_x = 38 + @max_y = 12 + @game_display_array = Array.new(@max_y) + @game_done = "no" + + @move_array = [0, 1, 2, 3, 4, 5, 6, 7, 8] + + self.clear_game_grid + + end + +#------------------------------------------------------- + + def render_char_at(x_loc, y_loc, render_char) + + if @max_x > x_loc && @max_y > y_loc + + temp_string = @game_display_array[y_loc] + temp_string[x_loc] = render_char + @game_display_array[y_loc] = temp_string + + end + + + end + +#------------------------------------------------------- + + def print_message(x_loc, y_loc, message) + + x_counter = 0 + + message.each_char do |individual_char| + self.render_char_at(x_loc+x_counter, y_loc, individual_char) + x_counter += 1 + end + + end + +#------------------------------------------------------- + + def clear_game_grid() + + line_counter = 0 + + while line_counter < @max_y do + + @game_display_array[line_counter] = " "*@max_x + line_counter += 1 + + end + + end + +#------------------------------------------------------- + + def get_game_grid() + + @game_display_array + + end + + +end # Of class. + +#============================================================= + +class Tic_tac_toe < Games + + def initialize + + @x_img = Array["X X "," X "] + @o_img = Array[" OO ","O O"] + @game_board = " E000 | E111 | E222 : M000 | M111 | M222 : E000 | E111 | E222 : ------|------|------ : E333 | E444 | E555 : M333 | M444 | M555 : E333 | E444 | E555 : ------|------|------: E666 | E777 | E888 : M666 | M777 | M888 : E666 | E777 | E888 " + @draw_x_loc = 5 + + @move_array = [0, 1, 2, 3, 4, 5, 6, 7, 8] + + @user_move = [] + @computer_move = [] + + @turn = "user" + @game_done = "no" + + super + + end + +#------------------------------------------------------- + + def reset_game + + @move_array = [0, 1, 2, 3, 4, 5, 6, 7, 8] + + @user_move = [] + @computer_move = [] + + @game_board = " E000 | E111 | E222 : M000 | M111 | M222 : E000 | E111 | E222 :------|------|------ : E333 | E444 | E555 : M333 | M444 | M555 : E333 | E444 | E555 :------|------|------: E666 | E777 | E888 : M666 | M777 | M888 : E666 | E777 | E888 " + + + @turn = "user" + + @game_done = "no" + + end + +#------------------------------------------------------- + + def player_move(row, column) + + move_num = row*3+column + + if move_available(move_num) + @user_move << move_num + @move_array.delete(move_num) + @turn = "computer" + end + + end + +#------------------------------------------------------- + + def computer_move + + if @turn == "computer" + + random_number = @move_array.sample + + random_row = random_number / 3 + random_column = random_number % 3 + + @move_array.delete(random_number) + + @computer_move << random_number + + @turn = "user" + + end + + + end + +#------------------------------------------------------- + + def get_game_state + + state_message = "no_wins" + + if is_draw == "yes" + state_message = "Draw" + + elsif is_win(@user_move) == "yes" + state_message = "You win" + + elsif is_win(@computer_move) == "yes" + state_message = "Computer wins" + + end + + state_message + + end # Of method. + +#------------------------------------------------------- + + def is_win(move_array) + + is_winner = "no" + + winning_combos = [[0,1,2],[3,4,5],[6,7,8],[0,3,6],[1,4,7],[2,5,8],[0,4,8],[2,4,6]] + + winning_combos.each do |combo_number_array| + + intersecting_array = move_array & combo_number_array + + if intersecting_array.length == 3 + is_winner = "yes" + @game_done = "yes" + + break + end + + + end # Of outer loop. + + is_winner + + end # Of method. + + +#------------------------------------------------------- + + def is_draw + + game_is_draw = "no" + + if @move_array.length == 0 + game_is_draw = "yes" + @game_done = "yes" + + end + + end # Of method. + +#------------------------------------------------------- + + def move_available(move_number) + + @move_array.include?(move_number) + + end # of method. + +#------------------------------------------------------- + + def render_game_board + + + #Reset board to be re-drawn + + @game_board = " E000 | E111 | E222 : M000 | M111 | M222 : E000 | E111 | E222 :------|------|------ : E333 | E444 | E555 : M333 | M444 | M555 : E333 | E444 | E555 :------|------|------: E666 | E777 | E888 : M666 | M777 | M888 : E666 | E777 | E888 " + + # Render user moves first : + #@user_move + #@computer_move + #@game_board + + @user_move.each do |user_num| + + middle_repl_string = "M"+user_num.to_s*3 + edge_repl_string = "E"+user_num.to_s*3 + + @game_board = @game_board.gsub(middle_repl_string, @x_img[1]) + @game_board = @game_board.gsub(edge_repl_string, @x_img[0]) + + end # Of render loop. + + + # Now the computer moves + + @computer_move.each do |comp_num| + + middle_repl_string = "M"+comp_num.to_s*3 + edge_repl_string = "E"+comp_num.to_s*3 + + @game_board = @game_board.gsub(middle_repl_string, @o_img[1]) + @game_board = @game_board.gsub(edge_repl_string, @o_img[0]) + + end # Of render loop. + + # Finally, clean up : + + counter = 0 + while counter < 9 do + + middle_repl_string = "M"+counter.to_s*3 + edge_repl_string = "E"+counter.to_s*3 + + @game_board = @game_board.gsub(middle_repl_string, " ") + @game_board = @game_board.gsub(edge_repl_string, " ") + + counter += 1 + + end # Of render loop. + + @game_display_array = @game_board.split(":") + + #---------------TEST ONLY ------------------- : + + #@game_display_array.each do |display_line| + # puts "--> #{display_line}" + #end # of test display + + #puts " " + #puts " " + #puts "Movement array ->>>> #{@move_array}" + + @game_display_array + + + end # Of method. + +#------------------------------------------------------- + + def game_done + + @game_done + + end + +#------------------------------------------------------- + + + +end # Of class + +#============================================================= + + +class Hangman < Games + + def initialize + + @word_url = "https://random-word-api.vercel.app/api?words=1" + @hang_counter = 0 + + # For screen real estate purposes, let's limit the word length + # to 14 letters : + @ultimate_word_length = 14 + @correct_guess_counter = 0 + @picked_word = "" + @guessed_word = "" + + super + + end + +#------------------------------------------------------- + + def draw_gallows + + self.print_message(0,0, " |-----|") + + for count in 1..8 + self.print_message(0,count, " |") + end + + self.print_message(0,9, "==|") + + + end + +#------------------------------------------------------- + + def draw_man + + case @hang_counter + when 1 + # Draw head + self.print_message(7, 1, " O ") + self.print_message(7, 2, " O O ") + self.print_message(7, 3, " O ") + + when 2 + # Draw the body + self.print_message(7, 4, " | ") + self.print_message(7, 5, " | ") + self.print_message(7, 6, " | ") + self.print_message(7, 7, " | ") + + when 3 + # Draw the left arm + self.print_message(7, 5, " /| ") + self.print_message(7, 6, "/ | ") + + when 4 + # Draw the right arm + self.print_message(7, 5, " /|\\") + self.print_message(7, 6, "/ | \\") + + when 5 + # Draw the left leg + self.print_message(7, 8, " /") + self.print_message(7, 9, "/ ") + + when 6 + # Draw the right leg + self.print_message(7, 8, " / \\") + self.print_message(7, 9, "/ \\") + end + + + end # Of method + +#------------------------------------------------------- + + def pick_word + + @picked_word = HTTP.get(@word_url).to_s + + word = @picked_word + + word = word.gsub(/[^a-z ]/i, '') + + @picked_word = word + + word_length = word.length + + while word_length > @ultimate_word_length + @picked_word = HTTP.get(@word_url) + end + + temp_string = "" + + word.each_char do |letter| + + temp_string += "_" + + end + + @guessed_word = temp_string + + + end + +#------------------------------------------------------- + + def draw_word + + self.print_message(0, 11, @guessed_word) + + end # Of method + +#------------------------------------------------------- + + def check_picked_letter(picked_letter) + + guessed_correctly = "no" + + picked_letter = picked_letter.upcase + + temporary_word = @picked_word.upcase + temp_guessed_word = @guessed_word + + array_counter = 0 + temporary_word.each_char do |letter| + + if letter == picked_letter + temp_guessed_word[array_counter] = picked_letter + @correct_guess_counter += 1 + guessed_correctly = "yes" + + end + array_counter += 1 + + end # Of loop. + + #........................ + + @guessed_word = temp_guessed_word + + if guessed_correctly == "no" + @hang_counter += 1 + end + + + end + +#------------------------------------------------------- + + def win_or_lose + + win_lose = "dontknow" + + # Check to see if we lost : + if @hang_counter == 6 + win_lose = "lost" + @game_done = "yes" + self.print_message(10, 5, "Sorry,") + self.print_message(10, 6, "You were HANGED!!") + self.print_message(0, 11, @picked_word.upcase) + end + + if @correct_guess_counter == @picked_word.length + win_lose = "won" + @game_done = "yes" + self.print_message(10, 5, "Congratulations,") + self.print_message(10, 6, "No hanging this time!!") + + end + + win_lose + + + end + +#------------------------------------------------------- + + def reset_game + + @hang_counter = 0 + @correct_guess_counter = 0 + pick_word + + self.clear_game_grid + + @game_done = "no" + + + end + +#------------------------------------------------------- + + def update_screen + + # Let's draw the gallows and the unlucky guy : + + draw_gallows + draw_man + draw_word + + @game_display_array + + end # Of method + +end # Of class diff --git a/render.yaml b/render.yaml index 814a0b4..b99513d 100644 --- a/render.yaml +++ b/render.yaml @@ -1,6 +1,6 @@ services: - type: web - name: MYAPPNAME # the name of this service, eg hello-world + name: omnicalc4 # the name of this service, eg hello-world env: ruby # this app is written in ruby plan: free # make sure to set this to free or you'll get billed $$$ buildCommand: "./bin/render-build.sh" # # we already created these two files for you diff --git a/views/basic_calculator.erb b/views/basic_calculator.erb new file mode 100644 index 0000000..4720373 --- /dev/null +++ b/views/basic_calculator.erb @@ -0,0 +1,24 @@ + + + diff --git a/views/fonts/Calculator.ttf b/views/fonts/Calculator.ttf new file mode 100644 index 0000000..8d74251 Binary files /dev/null and b/views/fonts/Calculator.ttf differ diff --git a/views/fonts/SFDigitalReadout-MediumObli.ttf b/views/fonts/SFDigitalReadout-MediumObli.ttf new file mode 100644 index 0000000..ad0656a Binary files /dev/null and b/views/fonts/SFDigitalReadout-MediumObli.ttf differ diff --git a/views/fonts/open-sauce.sans-black.ttf b/views/fonts/open-sauce.sans-black.ttf new file mode 100644 index 0000000..ea2105d Binary files /dev/null and b/views/fonts/open-sauce.sans-black.ttf differ diff --git a/views/games_calculator.erb b/views/games_calculator.erb new file mode 100644 index 0000000..2142e1d --- /dev/null +++ b/views/games_calculator.erb @@ -0,0 +1,78 @@ + + + <% if @game_selected == "tic-tac-toe" %> + + + + <% elsif @game_selected == "hangman" %> + + + + <% end %> + + + + diff --git a/views/gpt_calculator.erb b/views/gpt_calculator.erb new file mode 100644 index 0000000..5c013f2 --- /dev/null +++ b/views/gpt_calculator.erb @@ -0,0 +1,13 @@ + + + diff --git a/views/layout.erb b/views/layout.erb index d0e831e..4794f32 100644 --- a/views/layout.erb +++ b/views/layout.erb @@ -1,12 +1,41 @@ -