Building a Ruby calcualtor > Problems with decimals - ruby

I'm building a simple calculator in Ruby using Green Shoes, a graphics toolkit. This calculator should work similar to the standard Windows Calculator, with the ability to perform */+= functions on integers and decimals (fractions) and output values rounded to the 100th place.
So far, the calculator can add/subtract/multiply/divide integers and output integers. For example, 6/5=1, 8/3=2, and 1/2=0. The is the first issue, as I want the calculator to output values rounded to the 100th place.
The second issue regards inputs, as calculator does not currently recognize floating points when entering value. This is probably due to the fact that I haven't assigned any variables/functions to my . decimal button.
My code is as follows:
require 'green_shoes'
Shoes.app(title: "Ford's calculator", width: 200, height: 260) do
number_field = nil
#number = 0
flow width: 200, height: 260 do
flow width: 0.7, height: 0.2 do
number_field = para #number, margin: 10
end
flow width: 0.3, height: 0.2 do
background rgb(232, 161, 0)
button 'Clr', width: 1.0, height: 1.0 do
#number = 0
number_field.replace(#number)
end
end
flow width: 1.0, height: 0.8 do
background rgb(50, 205, 50)
%w(7 8 9 + 4 5 6 - 1 2 3 / 0 . = *).each do |btn|
button btn, width: 50, height: 50 do
case btn
when /[0-9]/
#number = #number.to_i * 10 + btn.to_i
when '='
#number = #previous.send(#op, #number)
else
#previous, #number = #number, nil
#op = btn
end
number_field.replace(#number)
end
end
end
end
end
So my questions are as follows:
What do I need to add to my code to make the app INPUT floating
points in terms of capturing variables?
What do I need to add to my code to make the app OUTPUT numbers
rounded to the 100th place instead of rounding to whole numbers?
Thanks in advance! And if there's any clarification you guys need in re: requirements, etc., let me know!

To convert a String to a Float:
"3.41".to_f # 3.41
#input = #input.to_f # Convert String #input to a Float
To print a number with max x decimals, use round:
3.412631.round(2) # 3.41
3.412631.round(100) # 3.412631

Related

d3.scaleLog ticks with base 2

I trying to produce ticks for scaleLog().base(2).
Seems to be, it does not work correctly.
For instance, for the call:
d3.scaleLog().base(2).domain([50,500]).ticks(10)
I got:
[ 50, 100, 150, 200, 250, 300, 350, 400, 450, 500 ]
Which just linear placed ticks. For base(10) it works properly.
d3.scaleLog().base(10).domain([50,500]).ticks(10)
[ 50, 60, 70, 80, 90, 100, 200, 300, 400, 500 ]
I using d3.js version 6.1.1.
I am missing something?
You're not missing anything, but there is this line, inside the source code:
if (z.length * 2 < n) z = ticks(u, v, n);
Here, z is the generated array (in this case [64, 128, 256]), n is the required number of ticks (10), and u and v are the domain (50 and 500).
Because the number of generated ticks is too low, d3 defaults to a linear scale. Try one of the following instead:
console.log(d3.scaleLog().base(2).domain([50, 500]).ticks(6));
console.log(d3.scaleLog().base(2).domain([32, 512]).ticks(10));
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.1.1/d3.min.js"></script>
If all parameters are variable, you could calculate the maximum possible number of ticks and use that as an upper bound:
const domain = [50, 500];
const ticks = 100;
console.log(d3.scaleLog().base(2).domain(domain).ticks(ticks));
function getNTicks(domain, ticks) {
const maxPossibleTicks = Math.floor(Math.log2(domain[1]) - Math.log2(domain[0]));
return Math.min(ticks, maxPossibleTicks);
}
console.log(d3.scaleLog().base(2).domain(domain).ticks(getNTicks(domain, ticks)));
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.1.1/d3.min.js"></script>

How do I get buttons to do things for gui hangman

I am new to python and have decided to create a hangman game as a GUI with tkinter. I have stumbled across this problem where I can't get my buttons to do what I want. Specifically, I want them to check if the letter is in the mystery word and print it in the position of the letter in the word if it is. Any tips or suggestions will be helpful.
from tkinter import *
import random
from tkinter import Label, Canvas
root = Tk()
root.title("Hangman Project")
c: Canvas = Canvas(root, height=500, width=500, bg="white")
c.pack()
height = 400
width = 400
head = c.create_oval(70, 70, 130, 130)
neck = c.create_line(100, 130, 100, 150)
body = c.create_rectangle(70, 150, 130, 220, fill="orange")
arm1 = c.create_line(130, 170, 150, 120)
arm2 = c.create_line(70, 170, 50, 120)
leg1 = c.create_line(110, 220, 145, 275)
leg2 = c.create_line(90, 220, 55, 275)
def gallows():
c.create_line(width / 40, height / 8, width / 4, height / 8)
c.create_line(width / 40, height / 8, width / 40, height / 1.6)
c.create_line(0, height / 1.6, width / 20, height / 1.6)
c.create_line(width / 40, height / 5, width / 4, height / 8)
c.create_line(width / 4, height / 8, width / 4, height / 5.7)
line = """Antiquated outdated fashioned Choleric easily angered Diorama
model scene Fecund fertile Inebriation drunkenness intoxication Marshal gather
together Parity equality Profound meaning Servile overly submissive groveling Usurp
"""
line.lower()
word_list = list(line.split(" "))
correct_ans = word_list
prize_word = random.choice(word_list)
spaces = " ".join(prize_word)
mystery_word = " ".join("_" * len(prize_word))
y = Label(root, text=mystery_word, font="Times, 30")
y.place(x=190, y=300)
def makebuttons():
count = 0
lst = []
if count <= 27:
for letter in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ':
lst.append(letter)
for letter in lst:
Buttons = Button(master=root, text=letter, font="Times, 20")
Buttons.pack()
Buttons.place(x=20 * count, y=460)
count += 1
makebuttons()
gallows()
root.mainloop()
There are several issues in your code:
line.lower() will not modify line, so use line = """...""".lower() instead
line.split() will contain "" and "\n" which need to be filtered out
redundant code in makebuttons(): if statement is not necessary and the two for loops can be merged into one
Below is a modified version of part of your code with a new function check_letter() which will be executed when a letter button is clicked:
line = """Antiquated outdated fashioned Choleric easily angered Diorama
model scene Fecund fertile Inebriation drunkenness intoxication Marshal gather
together Parity equality Profound meaning Servile overly submissive groveling Usurp
""".lower()
word_list = [x for x in line.split(" ") if x != "" and x != "\n"] # filter out all "" and "\n"
prize_word = list(random.choice(word_list)) # use list instead of string for easy modification
print(prize_word)
mystery_word = ["_"] * len(prize_word) # use list instead of string for easy modification
y = Label(root, text=mystery_word, font=("Times", 30))
y.place(x=190, y=300)
def check_letter(c):
found = False
for i, letter in enumerate(prize_word):
if c == letter:
prize_word[i] = "-"
mystery_word[i] = c # update the guess result
found = True
if found:
y['text'] = mystery_word
else:
# do whatever you want if letter is not found
pass
def makebuttons():
for i,letter in enumerate("abcdefghijklmnopqrstuvwxyz"):
Button(root, text=letter, font=("Times", 14), width=2, command=lambda c=letter: check_letter(c)).place(x=30*i+10, y=460)
You need to modify check_letter() function to cater two situations:
when all letters in the mystery word are found
when the letter is not found in the mystery word
Hope this help.

Position circles around a circle given x circles with fixed diameter in SASS

A question of two parts:
End goal is something like this, ala graph DB visualisers - but in html / css/sass
Part 1: How to position x number of circles around a circle so the edges touch (or prefereably, with a little whitespace).
For example, this is what i'm going for given 3, 6 and 7 circles.
I'm trying to get it working using SASS, however if there's a library or something that does what I'm after i'd rather use that - i'm just struggling to formulate the search phrase.
I'm using the trig functions from here, and stole the circle arrangement from here.
CODEPEN of what I've got so far.
I'm bad at maths, but some friends gave me the fomula you'll find below that should work out the distance to the outer circle center. $distance: tan((180-($angle))/2) * $radius;. However its not doing as i expect - given 6 circles, with a diameter of 100 I'd expect an output of 100, but i'm getting 86.602...
Here's the sass - probably easier to look in the codepen though.
#function strip-unit($number) {
#if type-of($number) == 'number' and not unitless($number) {
#return $number / ($number * 0 + 1);
}
#return $number;
}
#mixin on-circle($item-count, $circle-size, $item-size, $break-at) {
position: relative;
height: $circle-size;
padding: 0;
border-radius: 50%;
list-style: none;
>* {
display: block;
position: absolute;
top: 50%;
left: 50%;
width: $item-size;
height: $item-size;
margin: -($item-size / 2);
$angle: (360 / $break-at);
$rot: 0;
$prevLayer: 0;
#for $i from 1 through $item-count {
$layer: ceil($i/ $break-at);
$layerMinusOne: $layer - 1;
// MoveX figured out by aligning stuff by eye
// item-count 3 4 5 6 7 8 9 10 ...12 13 14...20
// moveX (%) 57 70 85 100 115 130 145 160 192 207 225 315
$item-radius: strip-unit($item-size) / 2;
// !! This is where i'm having trouble
$distance: tan((180-($angle * 1deg))/2) * $item-radius;
#debug "tan((180-#{$angle})/2) * #{$item-radius} = #{$distance}";
$moveX: ( $distance / strip-unit($item-size)) * 100 * 1%;
#debug "moveX: #{$moveX}";
#if $layer != $prevLayer {
$prevLayer: $layer;
$rot: $rot + $angle/2;
}
&:nth-of-type(#{$i}) {
transform:
// !! This is where the 'percent of circle diameter' measurements come in, translateX uses the size of the element being transformed when % is used.
rotate($rot * 1deg) translateX($moveX * $layer) rotate($rot * -1deg);
}
$rot: $rot+$angle;
}
}
}
$numOfCircles: 3; // <- Change me in the codepen
.circle-container {
#include on-circle($item-count: 28, $circle-size: 200px, $item-size: 50px,
$break-at: $numOfCircles);
margin: 5em auto 5em;
border: solid 5px red;
.around-a-circle {
text-align: center;
border-radius: 50%;
border: solid 1px #118be1;
}
}
Part 2: The extra layers.
My end goal as seen above is to display x number of circular elements in rings, where the inner most ring is made up of y elements and bubbles out from there.
As i said i'd rather use a library, but i couldn't find anything that does what i want. I was going to use the inner ring as a starting point and each alternating layer, rotate an extra bit and place the element nestled between the previous rings elements, but again i'm struggling with the dimensions, and how much to offset by.
$layer: ceil($i/ $break-at);
...
#if $layer != $prevLayer {
$prevLayer: $layer;
$rot: $rot + $angle/2;
}
The above code does that, mostly, however the spacings aren't optimised and the whitespace is too much compared to my end goal photo.
The distance needs to be between center of circle 1 and center of circle 2 and half that is your radius for all the circles.
I don't know sass so here is a working JS version as proof that this works.
https://jsfiddle.net/hk5spy20/
If you change line 32-33 from
var x1 = pointXY[0].x;
var y1 = pointXY[0].y;
to
var x1 = xPos;
var y1 = yPos;
You will replicate what you are currently doing which results in overlapping circles.
***** Added *****
The way you have the 2nd, 3rd, 4th level bubbles working will become gappy as you expand out because of the radius of the circle increases in size.
It won't work this way.
I have something but require work but I have this so far... https://jsfiddle.net/hd7qp06b/2/
I think for each row you will need two different set of formulas to get this working perfectly, the second row works, the 3rd row doesn't which is where a new formula is required. Will come back to this.
This seems to work: https://jsfiddle.net/eo170zsu/
You have to keep a track of pair adjacent bubbles and attachBubble next to it. If you put the co-ordinate of bubble 9 and 15 on the stack, it'll place new bubble perfectly next to it. However, you can't put bubble 9 and 16 on stack as well because this would cause an overlap. There is a sequence of pairs that are safe and probably be consistent for certain levels, I suspect odd / even levels has different rules for pairing.
Actually, thinking about it, just pair 9,15 and 9,16 process each one and if there is an overlap between two circles on screen, throw it away and try next pair.

Ruby green shoes timer

I'm building this popup countdown timer for a game. The issue is I can't figure out how to update the the animate so that the display changes too. It works so far, but you can't see the numbers changing. It blends into the 00:00. I'm pretty positive it works so far just having trouble with this change. This is done with green shoes. Any ideas what I'm doing wrong here?
#Timer button used for creating a countdown timer for the game.
#Game ends when timer is zero.
flow width: 80, height: 0.2 do
button 'Timer', width: 1.0, height: 1.0 do
window do
def time_change!
#clock = '%02d:%02d' % [#second / 60, #second % 60]
if(#second == 0)
alert "game is over"
#clock = '00:00'
close()
para #clock, size: 50, stroke: black
end
end
background whitesmoke
#clock = '00:00'
para #clock, size: 50, stroke: black
#second = 10
animate(1) do
#second -= 1
time_change!
para #clock, size: 50, stroke: black
end
end
end
You can replace the text of the current para which displays the clock:
Shoes.app do
flow do
button 'Timer', width: 100, height: 50 do
window width: 200, height: 100 do #Open a child window when the button is clicked
seconds = 3
tenths = 0
clock = '%02d:%02d'
flow do
#p = para clock % [seconds, tenths], #Assign the clock para to an instance variable,
size: 50, #which will make the variable visible outside this block.
stroke: black
end
a = animate(10) do #Upate the clock every 1/10 of a second.
tenths -= 1
if tenths < 0
tenths = 9
seconds -= 1
end
#p.text = clock % [seconds, tenths] #Replace the clock text.
if seconds == 0 and tenths == 0
a.stop
alert("game over")
close #=>self.close where self is the window whose block contains this code
end
end #animate
end #window
end #button
end #flow
end #app
To verify that the clock is actualy showing each time increment, you can slow things down by changing animate(10) to animate(1).

How do I change the font color in VB6?

I have some code that displays values from a record set. If the value is less than 8000, I wish to change the color of the displayed text. I tried this:
If (recordset(1).Value) < 80000 Then
font.color = &HFFEFEF
End If
But it didn't work. How do I do it?
Addon to raven's answer.
You can also use:
Text1.ForeColor = vbBlack
'vbBlack, vbWhite, vbBlue, vbRed, vbGreen, vbYellow, vbMagenta, vbCyan
and
Text1.ForeColor = RGB(255, 0, 0 ) 'red
0, 0, 0 - black
255, 255, 255 - white
255, 0, 0 - red
0, 255, 0 - green
0, 0, 255 - blue
255, 255, 0 - yellow
0, 255, 255 - cyan
255, 0, 255 - magenta
You don't specify how you are displaying the information, but if you're using a TextBox, you would changed the text color via the ForeColor property
Text1.ForeColor = &HFFEFEF
Changing the forecolor of the textbox/label inside each conditions may do the trick. For example I want to input an integer and I want to know if the integer I've entered is ODD or EVEN.
The deal is:
If the integer is an ODD, it will display as a RED text in the label,
else if it is EVEN, it will display as blue in the label.
Take this as an example:
Input number: text1
Output: label1
Code:
if (val(text1) mod 2) = 1 then
label1 = "ODD"
label1.Forecolor = vbRed
else
label1 = "EVEN"
label1.Forecolor = vbBlue
end if
*mod is a modulo operator function used to take the remainder of the text1 divided by 2?

Resources