Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
moosferatu
Jan 29, 2020
They're probably trying to get you to write it using recursion. For example, have a function that takes as input the current player and scores, and then execute your turn logic. If a player has won return the results, otherwise call the same function again with the updated values.

Aside, when a 1 is rolled do you really accumulate the turn score and not go bust? If so, why would you ever not roll?

Adbot
ADBOT LOVES YOU

Tempora Mutantur
Feb 22, 2005

moosferatu posted:

They're probably trying to get you to write it using recursion. For example, have a function that takes as input the current player and scores, and then execute your turn logic. If a player has won return the results, otherwise call the same function again with the updated values.

that's the right interpretation

or be an rear end in a top hat and write it as an event-driven score system using a single for loop which has its value change to the current highest score after each iteration; each iteration emits a currentPlayerRoll event handled by a currentPlayerRollHandler which does all the score/turn keeping and has a handy function that also updates the variable tracking the for loop and current player so the game ends when a single unbroken for loop runs to completion to 100 and it's completely over-engineered in response to "no while loops"

RPATDO_LAMD
Mar 22, 2013

🐘🪠🍆
Yeah those requirements definitely point towards the prof wanting you to use a specific technique, probably based on whatever's been in the lectures recently.

Avoiding loops entirely by using recursion is probably the easiest way to do it.
Still I'd be kinda surprised if a prof handed an assignment like that out without specifically saying "use recursion", especially with the weird restriction that for loops are ok but while loops are not.

Other notes if you wanna take a non-recursive approach:
Instead of break, you can always get out of a loop with return. of course this requires separating each loop out into its own function instead of putting them all in one big one.
If you're a real sicko you can do it by raising and catching exceptions too! (Don't do that.)

if you want an infinite loop without using while, you can use generator functions, for example
Python code:
import itertools
for x in itertools.repeat(0):
    print(f"x is {x}. I'm looping forever!")
will print "x is 0. I'm looping forever!" infinite times until you kill it.

But this is also kinda stupid and is basically just a dumber way to write a while loop. Unless your teacher specifically wanted you to write/use a generator function just for the sake of writing one, so again I guess check the recent lecture topics?

Tempora Mutantur posted:

that's the right interpretation

or be an rear end in a top hat and write it as an event-driven score system using a single for loop which has its value change to the current highest score after each iteration; each iteration emits a currentPlayerRoll event handled by a currentPlayerRollHandler which does all the score/turn keeping and has a handy function that also updates the variable tracking the for loop and current player so the game ends when a single unbroken for loop runs to completion to 100 and it's completely over-engineered in response to "no while loops"

in python, unlike C, you can't overwite the variable controlling a for loop. Every loop is basically range-based for.

Though you can still hack around it with a generator that depends on some external state, like like this one made with iter:
Python code:
done = False
def is_done(): 
	return done

sentinel_value = True
# this will iterate by calling is_done() over and over until it returns the sentinel value
is_it_done_yet_generator = iter(is_done, sentinel_value)
for _ in is_it_done_yet_generator:
	# do something

	if .... :
		done = True # break the loop
that's an extra dumb way to get around using break though so only use it if you feel like being a clever rear end in a top hat

RPATDO_LAMD fucked around with this message at 04:30 on May 4, 2024

leper khan
Dec 28, 2010
Honest to god thinks Half Life 2 is a bad game. But at least he likes Monster Hunter.
code:

for (;;) {
}

cheetah7071
Oct 20, 2010

honk honk
College Slice
every time I've tried to use recursion in a non-toy piece of code I've immediately run out of stack space and been forced to rewrite it as a while loop lol

mystes
May 31, 2006

cheetah7071 posted:

every time I've tried to use recursion in a non-toy piece of code I've immediately run out of stack space and been forced to rewrite it as a while loop lol
It works better in languages with tail call optimization

RPATDO_LAMD
Mar 22, 2013

🐘🪠🍆
also depends on what exactly you're doing, like recursively walking a tree or doing any kind of binary search thing will only use log(n) stack space

KillHour
Oct 28, 2007


I've been doing a lot of work with data-driven execution in shaders and let me tell you, not having a call stack at all breaks you in ways I can't even describe.

I can flatten a directed acyclic graph into a for loop in my sleep. Structs? Maybe if you don't care about cache coherency. We only do arrays of 4 component vectors here, buddy!

Volmarias
Dec 31, 2002

EMAIL... THE INTERNET... SEARCH ENGINES...

A Festivus Miracle posted:

Hey Goons, your gracious assistance please.

So, I wrote a game of Pig, which is a dice game in which two players roll a dice, and then add that dice roll to their score. First to 100 wins. The catch is, if you roll a one, your turn ends and the turn switches to Player 2.
For ease of testing, I set the win condition for the code at 30.

This was for an assignment. My professor said 'no while loops' so I refactored the code into two long for loops. And of course, professor says "we don't break out of loops in this class". So, uh. Here's the code

pre:
#this program simulates a game of pig

import random
import time

player_one_score = 0
player_two_score = 0
current_player = "Player One"

for game_round in range(1, 101):#using an extremely long for loop to simulate 100 rounds
    print(f"It's {current_player}'s turn.")
    turn_score = 0

    for roll_count in range(40): #going to be randomly extremely statistically unlikely to reach this limit
        roll = random.randint(1, 6)
        print(f"{current_player} rolls a {roll}")
        time.sleep(1)#for ease of play

        if roll == 1:
            print("You rolled a 1. Switching to the other player's turn.")
            time.sleep(1)
            if current_player == "Player One":
                player_one_score += turn_score
                current_player = "Player Two"
            else:
                player_two_score += turn_score
                current_player = "Player One"
            break
        else:#if player doesn't roll a one, asks user if they want to roll again
            turn_score += roll
            print(f"{current_player}'s score: {player_one_score + turn_score if current_player == 'Player One' else player_two_score + turn_score}")

        choice = input("Roll again? (y/n): ").lower()#lower to filter input
        if choice == 'n':#not a super fan of this, but it works
            if current_player == "Player One":
                player_one_score += turn_score
                current_player = "Player Two"
            else:
                player_two_score += turn_score
                current_player = "Player One"
            break

    if player_one_score >= 30 or player_two_score >= 30:#from 100 to 30 so this doesn't take a super long time
        break

if player_one_score >= 30:
    print(f"Congratulations! Player One wins with a score of {player_one_score}")
if player_two_score >= 30:
    print(f"Congratulations! Player Two wins with a score of {player_two_score}")
This, well, sucks, but I'm working a full time job now so, I didn't have a super huge amount of time to dedicate to this. I'm not entirely sure how to replace the break statements without breaking the loops and I would appreciate some pointers in that direction.

As others mentioned, figure out what your professor is trying to get the class to do and do that. This is an extremely dumb way to try to teach people to use recursion if that is indeed the case; there's so many better examples that aren't terrible!

Also, saying "we don't use break statements" makes me want to say "ok cool,


code:

finish = [0]
for i in finish
  finish.append(0)
  ...
  if (we would break here)
    finish.pop()
    continue

  ...


I'm not using break here or while loops! We're good, right?" :fuckoff:

Volmarias fucked around with this message at 07:21 on May 4, 2024

CarForumPoster
Jun 26, 2013

⚡POWER⚡

Volmarias posted:

As others mentioned, figure out what your professor is trying to get the class to do and do that. This is an extremely dumb way to try to teach people to use recursion if that is indeed the case; there's so many better examples that aren't terrible!

Also, saying "we don't use break statements" makes me want to say "ok cool,

[...]

I'm not using break here or while loops! We're good, right?" :fuckoff:

Generally agree. I'm betting this is getting him to figure out recursion and probably to break nested for loops into a few functions that more clearly explain whats going on. Maybe something like this (generated with chatGPT, havent tested but it gets to the point)

code:
import random
import time

def roll_dice():
    return random.randint(1, 6)

def take_turn(current_player, player_one_score, player_two_score):
    print(f"It's {current_player}'s turn.")
    turn_score = 0

    def roll_again():
        nonlocal turn_score
        roll = roll_dice()
        print(f"{current_player} rolls a {roll}")
        time.sleep(1)  # for ease of play

        if roll == 1:
            print("You rolled a 1. Switching to the other player's turn.")
            time.sleep(1)
            return switch_player(current_player, turn_score, player_one_score, player_two_score)
        else:
            turn_score += roll
            print(f"{current_player}'s score: {player_one_score + turn_score if current_player == 'Player One' else player_two_score + turn_score}")
            choice = input("Roll again? (y/n): ").lower()
            if choice == 'n':
                return switch_player(current_player, turn_score, player_one_score, player_two_score)
            return roll_again()

    return roll_again()

def switch_player(current_player, turn_score, player_one_score, player_two_score):
    if current_player == "Player One":
        player_one_score += turn_score
        current_player = "Player Two"
    else:
        player_two_score += turn_score
        current_player = "Player One"
    
    if player_one_score >= 30 or player_two_score >= 30:
        return (player_one_score, player_two_score)
    
    return take_turn(current_player, player_one_score, player_two_score)

def play_game():
    player_one_score, player_two_score = take_turn("Player One", 0, 0)
    if player_one_score >= 30:
        print(f"Congratulations! Player One wins with a score of {player_one_score}")
    elif player_two_score >= 30:
        print(f"Congratulations! Player Two wins with a score of {player_two_score}")

play_game()

If you like discrete event simulations like this, I'd also suggest looking at SimPy. I've used it to do business predictions for the expected value of projects and made some surprisingly accurate predictions about the future. Prob gonna use a while loop tho.

CarForumPoster fucked around with this message at 20:37 on May 4, 2024

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
The trouble is that this is simply much clearer and easier with a while loop. If you want to solve puzzles, you should get your job done early and hit up logic-masters.de. This could legitimately be a setup for a lesson about why tools like while loops are still useful, although I’m not sure beginning programmers specifically need that lesson.

Volmarias
Dec 31, 2002

EMAIL... THE INTERNET... SEARCH ENGINES...

rjmccall posted:

The trouble is that this is simply much clearer and easier with a while loop. This could legitimately be a setup for a lesson about why tools like while loops are still useful, although I’m not sure beginning programmers specifically need that lesson.

Given that it would be specifically introducing them to an anti pattern (I'm not sure which one offhand but I'm sure one of them describes this!), it feels like it would be counter productive. I would like to know what the constraints actually are, and what the expected result is by the professor.


quote:

If you want to solve puzzles, you should get your job done early and hit up logic-masters.de.

How am I supposed to beat any high scores in TIS-100 with that attitude?

credburn
Jun 22, 2016
A tangled skein of bad opinions, the hottest takes, and the the world's most misinformed nonsense. Do not engage with me, it's useless, and better yet, put me on ignore.
Hey, gang! Those of you with lots of experience in coding, let me ask you: Is it more common to have variable assignments and the like with or without a space between the equal sign? What I mean is, it is my personal habit to do things like:

code:
class Example
     def __init__(self,  name = 'name',  age = 24, detail_1 = 'something', detail_2 = 'something else')
But frequently when I ask Chat-GPT for help with stuff, it returns things that get rid of the spaces. i.e. name='name',age=24, etc. I get that's more efficient but in practice is it much more common? Because if it is perhaps I ought to try to break my habit of spaces...

RPATDO_LAMD
Mar 22, 2013

🐘🪠🍆
in the end style really doesnt matter, just keep it consistent throughout a whole project
ideally you wanna set up an autoformatter like "Black" for python to run whenever you save and then just never think about it again.

raminasi
Jan 25, 2005

a last drink with no ice

RPATDO_LAMD posted:

in the end style really doesnt matter, just keep it consistent throughout a whole project
ideally you wanna set up an autoformatter like "Black" for python to run whenever you save and then just never think about it again.

This is 1000% correct, and I'll add that particular customs like this (e.g. regarding whitespace) vary between languages as well. In C#, for example, most codebases (but not all!) will put spaces around = characters like you tend to.

boofhead
Feb 18, 2021

Yeah just pick a style and formatter and don't worry about it

For a lot of languages though I think it's common to have a space when you're defining or setting a standalone variable but to have no space when setting default values for function arguments

redleader
Aug 18, 2005

Engage according to operational parameters

RPATDO_LAMD posted:

in the end style really doesnt matter, just keep it consistent throughout a whole project
ideally you wanna set up an autoformatter like "Black" for python to run whenever you save and then just never think about it again.

emphasizing this. get a formatter, use it, don't bother changing the defaults, accept what it puts out. you'll get used to it even if you don't like the output at first

(the next level is setting up something in your build step to fail if a file isn't formatted properly, but i guess you're not yet at a level where this would be relevant)

Presto
Nov 22, 2002

Keep calm and Harry on.
Put some spaces in. Otherwise it's hard to read and it looks like your code is late for something and it's frantically rushing to get there.

Dr. Stab
Sep 12, 2010
👨🏻‍⚕️🩺🔪🙀😱🙀
It's not really more efficient. Code that's harder to parse can cause issues if the code needs to be changed or debugged, slowing down progress.

If you're writing client side js in a context where shaving off bytes matters, write well formatted code and use a minifier.

Computer viking
May 30, 2011
Now with less breakage.

Dr. Stab posted:

It's not really more efficient. Code that's harder to parse can cause issues if the code needs to be changed or debugged, slowing down progress.

If you're writing client side js in a context where shaving off bytes matters, write well formatted code and use a minifier.

Yeah, this - and even if you don't use a minifier, compression will probably eat most of the difference anyway.

PhantomOfTheCopier
Aug 13, 2008

Pikabooze!
It's also a topic that nearly everyone will get wrong, because they'll approach it from their very narrow experience instead of invoking linguistics or psychology. The easiest way to see this is to pick what someone believes is an immutable rule of style then ask them to come up with all the exceptions to that rule. Justifications are likely to include "People do it that way" and "I think it's easier to read", but very little will be quantitative or even measurable.

Another fun exercise is to take someone's three "most important" rules and find contradictions.

Computer viking
May 30, 2011
Now with less breakage.

PhantomOfTheCopier posted:

It's also a topic that nearly everyone will get wrong, because they'll approach it from their very narrow experience instead of invoking linguistics or psychology. The easiest way to see this is to pick what someone believes is an immutable rule of style then ask them to come up with all the exceptions to that rule. Justifications are likely to include "People do it that way" and "I think it's easier to read", but very little will be quantitative or even measurable.

Another fun exercise is to take someone's three "most important" rules and find contradictions.

The inherent tension in source code is that it's meant to be parsed by both people and software. The software can ignore formatting, though - so you should write for other people. And nobody has yet come up with the one perfect guide for how to write and format English, so I see no reason to expect a decisive set of rules for code.

cruft
Oct 25, 2007

Cryptography question!

I'm trying to implement something like HashCash in JavaScript (it's not for cryptocurrency).

HashCash works by concatenating the date, some arbitrary string, a random number, and a counter, into a "header". This is then digested with SHA1. If the digest begins with twenty (20) 0 bits, it is considered valid. Otherwise, the counter is increased until the header is valid.

It wants the random number and counter to be base64-encoded. Base64-encoding anything other than a string in JavaScript is... inelegant at best.

From a set theory standpoint, base64-encoding the number accomplishes nothing. I could just "%s" the number (into something like "834729") and prove that there is a 1-to-1 and onto mapping from the official scheme to my scheme.

But will this cause any sort of issue with SHA1? Is there something happening with base64-encoded numbers that yields a more even distribution of SHA1 encodings than my "%s" encoding?

mystes
May 31, 2006

cruft posted:

Cryptography question!

I'm trying to implement something like HashCash in JavaScript (it's not for cryptocurrency).

HashCash works by concatenating the date, some arbitrary string, a random number, and a counter, into a "header". This is then digested with SHA1. If the digest begins with twenty (20) 0 bits, it is considered valid. Otherwise, the counter is increased until the header is valid.

It wants the random number and counter to be base64-encoded. Base64-encoding anything other than a string in JavaScript is... inelegant at best.

From a set theory standpoint, base64-encoding the number accomplishes nothing. I could just "%s" the number (into something like "834729") and prove that there is a 1-to-1 and onto mapping from the official scheme to my scheme.

But will this cause any sort of issue with SHA1? Is there something happening with base64-encoded numbers that yields a more even distribution of SHA1 encodings than my "%s" encoding?
I imagine it doesn't really matter and using base64 is probably just to keep the string shorter compared to using strings of numbers in base 10

RPATDO_LAMD
Mar 22, 2013

🐘🪠🍆
Although it looks like the sha1 algorithm works on blocks of 512 bytes so as long as it's within the range of 0 to 512, keeping the input shorter shouldn't really make a difference anyways

Computer viking
May 30, 2011
Now with less breakage.

One of the design goals for cryptographic hashes is to maximise the avalanche effect: Ideally, changing any one bit in the input should have a 50% chance of flipping each bit in the hash. I don't know how close SHA-1 gets, but I trust it to be competent enough that it doesn't matter that digits encoded in ASCII are identical in 4 of 8 bits.

Put another way, 1234 and "1234" contains the same amount of information, the redundant bits are just an encoding artifact.

Computer viking fucked around with this message at 20:01 on May 16, 2024

mystes
May 31, 2006

RPATDO_LAMD posted:

Although it looks like the sha1 algorithm works on blocks of 512 bytes so as long as it's within the range of 0 to 512, keeping the input shorter shouldn't really make a difference anyways
I think the intent is probably just to be shorter when sending the string over the network, not because it would affect the sha1 algorithm

Magnetic North
Dec 15, 2008

Beware the Forest's Mushrooms
I just realized that the phrase "don't roll your own crypto" has different meanings now. :(

PhantomOfTheCopier
Aug 13, 2008

Pikabooze!

cruft posted:


It wants the random number and counter to be base64-encoded. Base64-encoding anything other than a string in JavaScript is... inelegant at best.


But will this cause any sort of issue with SHA1? Is there something happening with base64-encoded numbers that yields a more even distribution of SHA1 encodings than my "%s" encoding?

Um, yes? Start by assuming that everything is proper binary, so 8 bits per character, heading into SHA1. If the random number and counter are 32 bits each, that's 64 bits of entropy into the hash. If instead they're limited to base64, each character carries only 6 bits of information, so there's only 48 bits of entropy. IE the "consecutive counter" actually isn't, so the search may take considerably longer or fail.

"%s" is even worse since 8 bytes would only carry 26 bits of entropy.

Jabor
Jul 16, 2010

#1 Loser at SpaceChem

PhantomOfTheCopier posted:

Um, yes? Start by assuming that everything is proper binary, so 8 bits per character, heading into SHA1. If the random number and counter are 32 bits each, that's 64 bits of entropy into the hash. If instead they're limited to base64, each character carries only 6 bits of information, so there's only 48 bits of entropy. IE the "consecutive counter" actually isn't, so the search may take considerably longer or fail.

"%s" is even worse since 8 bytes would only carry 26 bits of entropy.

This doesn't affect the running time at all. You could pick counter values entirely at random and you would expect it to take just as long to get a hit.

Computer viking
May 30, 2011
Now with less breakage.

PhantomOfTheCopier posted:

Um, yes? Start by assuming that everything is proper binary, so 8 bits per character, heading into SHA1. If the random number and counter are 32 bits each, that's 64 bits of entropy into the hash. If instead they're limited to base64, each character carries only 6 bits of information, so there's only 48 bits of entropy. IE the "consecutive counter" actually isn't, so the search may take considerably longer or fail.

"%s" is even worse since 8 bytes would only carry 26 bits of entropy.

I think numbers in javascript are 64-bit floats, but either way. If you're putting a 32-bit number in there, or the same 32-bit number rendered in ASCII digits, wouldn't that ultimately carry the same amount of entropy? You can reconstruct either of them from the other, so there's no information gained or lost.

This does, of course, assume that there are no length limitations. Given that he mentioned there's a free text field in there, I certainly hope it's not limited to just one SHA-1 block (of 512 bit/64 bytes).

cruft
Oct 25, 2007

Computer viking posted:

I think numbers in javascript are 64-bit floats, but either way. If you're putting a 32-bit number in there, or the same 32-bit number rendered in ASCII digits, wouldn't that ultimately carry the same amount of entropy? You can reconstruct either of them from the other, so there's no information gained or lost.

This does, of course, assume that there are no length limitations. Given that he mentioned there's a free text field in there, I certainly hope it's not limited to just one SHA-1 block (of 512 bit/64 bytes).

When I posted this I was thinking maybe one nerd would be nerdy enough to have opinions about esoteric cryptography and information theory. I love this forum :love:

So yes, unless I'm mistaken about information theory, it doesn't matter how you encode the numbers, the entropy is the same. The part I was unsure about was the SHA-1 algorithm: I suspected it didn't matter how you encoded it, but I've learned that when it comes to crypto, never assume.

In my particular thing, the free text field is going to be relatively small. I'm likely to use a UUID.

Anyway. I coded this all up in both JavaScript and then Go. JavaScript, as optimized as I can make it, takes around 30 seconds on average to find a 20-bit preimage input. Go, with hardly any optimization, takes about 1.2 seconds. The reference implementation takes under a second.

As part of the optimization of JavaScript, I created a whole new packed binary form of HashCash, though. So I'll be relying on good ol' Security Through Obscurity: hoping that it takes someone at least as long as it took me to code up a faster-running version of my proprietary algorithm, at which point the contest will be over. Those who keep things in the browser will be sufficiently slowed down.

In the unlikely event somebody starts to DoS us with account registration, we can disable it and ask people to register through IRC or postcard or whatever. If it happens a lot, well, I'll figure something else out I suppose.

Thanks for the suggestions and please don't let me stop you all from continuing to explore the nooks and crannies here. I love crypto and information theory, I'm here for it.

Adbot
ADBOT LOVES YOU

ultrafilter
Aug 23, 2007

It's okay if you have any questions.


cruft posted:

So yes, unless I'm mistaken about information theory, it doesn't matter how you encode the numbers, the entropy is the same.

Yep.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply