# Python for cubing programs?



## Rainbow Flash (Dec 5, 2014)

Hi everyone,

I am a beginner in programming and I have begun learning the basics of programming with Python 2.

My question is: 

How are some ways I can use my amateur programming skills in some way with connection to speedcubing? I've thought about making a timer, or an algorithm memorisation program, or maybe even a cube solver program, but I need some brainstorming from pros like you guys for a noob like me.

I'm at an early intermediate level with my 3x3 cube, with an average of around 27 seconds. I've also begun learning the Ortega method for the 2x2, and have been wondering if I could somehow write a program around the 2x2. Anyway, looking forward to replies...

print "Hello, speedcubing forums!"

Rainbow Flash


----------



## DeeDubb (Dec 5, 2014)

I also learned a little Python in college. It's a super fun programming language!

Honestly, as a beginning programmer, you probably won't be able to make anything that someone already hasn't done, but that shouldn't stop you from playing around with things.

Some fun things you could do

Basic:
Make random scramble generators. This should be pretty easy. Try to make it so it won't repeat the same moves back to back

Intermediate:
Make a timer. I have no idea how to mess with time stuff in Python, but it shouldn't be terribly difficult to start and stop the timer, and store the times somewhere, even calculate Ao5, Ao12, and Ao100.

Advanced:
Make an OLL/PLL practice tool. It would need you to be able to submit a list of OLL/PLL algorithms, it would need to reverse them to create the "practice scramble", display the practice scrambles randomly, and add your timer to time the results.


----------



## Randomno (Dec 5, 2014)

I often want to make stuff with Python or JS, but figure it's probably too tricky and just use Scratch.

Also why not Python 3?


----------



## AlexTheEmperor (Dec 5, 2014)

Randomno said:


> I often want to make stuff with Python or JS, but figure it's probably too tricky and just use Scratch.
> 
> Also why not Python 3?



Python 2 offers better input formatting and avoids some strange errors you can get with Python's unwillingness to shadow native types. I also think that 2 is the latest version to support pygame, making GUIs really easy to make.


----------



## Myachii (Dec 5, 2014)

I've been coding with Python for a year and a bit now, and I used Python 3 to make myself a simple over/under calculator, which tells me how many of the solves I paste in from GQTimer are below the time limit I specified. It was a really fun challenge, and I made a little average calculator to go with it 

If you just intend to use this yourself and want a challenge, I suggest making something similar to what I have done (array + readfile knowledge required) or something basic that you think would be handy for yourself to use. As said above, it probably isn't the best tool for making new things that have never been done before.



Rainbow Flash said:


> print "Hello, speedcubing forums!"









(use python 3 )


----------



## Randomno (Dec 5, 2014)

Myachii said:


> http://gyazo.com/b102710e825b3c9c3e093431b47cec57.png
> 
> (use python 3 )



Ugh, why did they change that in Python 3?


----------



## StachuK1992 (Dec 5, 2014)

Seems to be okay for these people:

https://github.com/search?l=Python&o=desc&q=rubik&s=updated&type=Repositories&utf8=✓


----------



## Myachii (Dec 5, 2014)

Randomno said:


> Ugh, why did they change that in Python 3?


Agreed... I'm doing my assessment in Python 3 and I always put "print varname" without the brackets xD


----------



## qqwref (Dec 5, 2014)

Rainbow Flash: I don't recommend trying to make something new right off the bat. Start with some simpler cubing programs that will help you or people you know, like an alg trainer or maybe a stripped-down version of a program that you already use. That will help you get used to programming cubing stuff without getting so bogged down by the details of all the features you would add if you could. Once you have a good feel for it, if you have an idea for something new, you'll have a much better chance of getting it to work well.




Randomno said:


> I often want to make stuff with Python or JS, but figure it's probably too tricky and just use Scratch.


I find Javascript really easy to play with, since you can just make a file and open it in a browser. That helped a lot when I was making sims and stuff. It's also easy to take code from another project since most source code can be viewed directly.


----------



## Myachii (Dec 5, 2014)

Stefan said:


> That's not at all what was said above. And Python is great for both new and old stuff.
> 
> 
> 
> ...



I'd post more often if it weren't for these kind of responses. I was only stating tips from my own personal experience, maybe they were wrong, but I am not too familiar with GUI's and I don't use them myself. In my opinion, they over-complicate something that wouldn't hurt to just be shown in the Python Shell.
I do admit that my post was factually incorrect, and I apologise for that. But I really would appreciate feedback that weren't as harsh.
I'm still fairly new to Python, so I don't yet know my way around it completely. All I was trying to do was help someone who is currently in the position I was in, that we were all in, and show him the way that I progressed, and that was to avoid GUI's for the time being.

I don't mean to cause an argument. I'm here for the same reason as everyone else: To communicate and share experiences/ideas with other people who share the same hobby. I'm sorry for stating my thoughts as proven facts instead of saying that they may not be correct.


----------



## Rainbow Flash (Dec 6, 2014)

OK thanks guys for all your info, especially DeeDubb.

I saw what you wrote, qqwref, and I agree that I should start with simple stuff. Is there any website where I could get examples of a simple Python code, or at least have someone on speedsolving.com undergo some pains for me and write an example of a simple code?

Thanks for bearing with the noob,
Rainbow Flash

P.S. (I have just found codecademy.com and I'm loving it. It also has tutorials for Javascript and stuff like that, so I'll look into all that...)


----------



## mark49152 (Dec 6, 2014)

Any thoughts on Python versus Perl?


----------



## StachuK1992 (Dec 6, 2014)

Python > Perl. Perl is a mess. Python is smooth.


----------



## Randomno (Dec 6, 2014)

Rainbow Flash said:


> P.S. (I have just found codecademy.com and I'm loving it. It also has tutorials for Javascript and stuff like that, so I'll look into all that...)



Yeah, I've used Codecademy a lot. If you take a break from a language though, it's best to restart from the beginning of a section.


----------



## mark49152 (Dec 6, 2014)

StachuK1992 said:


> Python > Perl. Perl is a mess. Python is smooth.


In what way? I know Perl well since the 90s so chose it to do my cubing project. I know nothing about Python except that it seems more popular these days.


----------



## ajayd (Dec 6, 2014)

Python's syntax is incredibly clean, whereas Perl has all these weird symbols and stuff. Besides that, Python just requires less words to do stuff, and the requirement of indents makes code really easy to read.


----------



## StachuK1992 (Dec 6, 2014)

My opinion is that python's syntax and existing/growing userbase makes it a much better language to deal with.

Python's easier. It's alive. I see no downside.


----------



## unsolved (Dec 7, 2014)

StachuK1992 said:


> My opinion is that python's syntax and existing/growing userbase makes it a much better language to deal with.
> 
> Python's easier. It's alive. I see no downside.



How is the executable speed versus other coding environments? Also, does anyone have a 4x4x4 brute force solving program in python? I'm getting to the point where my own 4x4x4 solver is ready for optimization now that it is executing properly.

By the way, in C, I was able to come up with a board design that can make any 4x4x4 move using only 6 lines of code. By that I mean, take a 4x4x4 cube, make a move such as R' or u2 or b, and only 6 lines of code are needed to update the cube to its new configuration. It makes for a pretty fast move generator.


----------



## StachuK1992 (Dec 7, 2014)

unsolved said:


> How is the executable speed versus other coding environments? Also, does anyone have a 4x4x4 brute force solving program in python? I'm getting to the point where my own 4x4x4 solver is ready for optimization now that it is executing properly.
> 
> By the way, in C, I was able to come up with a board design that can make any 4x4x4 move using only 6 lines of code. By that I mean, take a 4x4x4 cube, make a move such as R' or u2 or b, and only 6 lines of code are needed to update the cube to its new configuration. It makes for a pretty fast move generator.


Well, Python is a Very High Level programming language, and will naturally be factors slower than something written in C/C++.

That said, people have done some pretty fast things in other high-level programming languages (hell, JavaScript is surprising everyone with some performance gains!).

When it comes down to things, though, the algorithms you use are of course the most important thing.

I'd love to see that board design and the 6 lines that execute, in any language. 

[as far as I've seen, no decent 444 solver exists in python]


----------



## mark49152 (Dec 7, 2014)

unsolved said:


> can make any 4x4x4 move using only 6 lines of code


Do you mean 6 executed or 6 lines within a loop? I'd like to see that too.

I'm also interested in any examples of cube-related code in Python. Looking at examples is probably the best way of getting a feel for a language.


----------



## StachuK1992 (Dec 7, 2014)

Here's a random script I wrote years ago, that's sort of cubing related http://ideone.com/mfVk3

based off of Badmephisto's Gripper from years past.



After I wrote this, we recovered the original code, found here:http://www.cubing.net/software/


----------



## Stefan (Dec 7, 2014)

StachuK1992 said:


> Here's a random script I wrote years ago, that's sort of cubing related http://ideone.com/mfVk3
> 
> based off of Badmephisto's Gripper from years past.



That's quite un-pythonic, though, more like Java forced into Python. As a kind of challenge, allow me to rewrite it so it's actually Python (though I kept the non-standard indentation):
http://ideone.com/8tzvWi

For example:


```
for x in range(0, len(things)):
    handle(things[x])
```

That's rather an example for what *not* to do. Python is really beautiful and the above makes it look ugly. Compare it to how it looks when done properly:


```
for thing in things:
    handle(thing)
```

(Or where appropriate, use comprehensions or map or whatever)


----------



## unsolved (Dec 7, 2014)

StachuK1992 said:


> Well, Python is a Very High Level programming language, and will naturally be factors slower than something written in C/C++.
> 
> That said, people have done some pretty fast things in other high-level programming languages (hell, JavaScript is surprising everyone with some performance gains!).
> 
> ...



How is this for fast? 







I have 3 experimental versions of the program. One is slow and finds every possible solve to a scramble. One is fast and finds multiple solutions. One is ridiculously fast (shown above) and finds and least one, possibly more than one, optimal solution at the expense of doing a great deal of pruning.

It is so fast because each side of the 4x4x4 cube is just one 64-bit integer, 4 bits per "sticker," and I use 64-bit shifts, ANDs, and ORs to make moves, instead of using matrix swap operations.



mark49152 said:


> Do you mean 6 executed or 6 lines within a loop? I'd like to see that too.
> 
> I'm also interested in any examples of cube-related code in Python. Looking at examples is probably the best way of getting a feel for a language.



Board layout...


```
BYTE 01        BYTE 02         BYTE 03         BYTE 04         BYTE 05         BYTE 06          BYTE 07         BYTE 08             
<-------------> <-------------> <-------------> <-------------> <-------------> <-------------> <-------------> <------------->
0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0   = TOP
0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1   = FRONT
0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1   = RIGHT
0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1   = BOTTOM
1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1   = BACK
1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1   = LEFT
```

So each color sticker has a different number. Top = 2, Front = 3, Right = 5, Bottom = 7, Back = 11, Left = 13. Shown above in base-2, all 1's and 0's, using 4 bits per color.

So 2 = 0010, 3 = 0011, 5 = 0101, 7 = 0111, 11 = 1101, 13 = 1011.

Each row of 64 1's and 0's is one variable 64 bits in length. So making a move on the 4x4x4 cube becomes easy. Just shift and move the bits in clusters of 4 to their new destinations. The code below makes the move U on the 4x4x4 cube. I call it "T+" since that is how I used to write moves when I did not know the notation.


```
BITBOARD_4x4x4_CUBE T_PLUS(BITBOARD_4x4x4_CUBE original_4x4x4_cube)
{
		BITBOARD_4x4x4_CUBE new_cube;

		/**************************************************************************/
		/* Rotating the top will change something on every face except the bottom */
		/**************************************************************************/
		new_cube._4x4x4_bottom = original_4x4x4_cube._4x4x4_bottom;

		/******************************************************************************************/
		/* Entire row of cubes moves from right -----> front -----> left -----> back -----> right */
		/* new front = old right; new right = old back; new back = old left; new left = old front */ 
		/******************************************************************************************/
		new_cube._4x4x4_front = (original_4x4x4_cube._4x4x4_front & BITMASK_CUBE_FACE_NOT_ROW_01) | (original_4x4x4_cube._4x4x4_right & BITMASK_CUBE_FACE_ROW_01);
		new_cube._4x4x4_right = (original_4x4x4_cube._4x4x4_right & BITMASK_CUBE_FACE_NOT_ROW_01) | (original_4x4x4_cube._4x4x4_back  & BITMASK_CUBE_FACE_ROW_01);
		new_cube._4x4x4_back  = (original_4x4x4_cube._4x4x4_back  & BITMASK_CUBE_FACE_NOT_ROW_01) | (original_4x4x4_cube._4x4x4_left  & BITMASK_CUBE_FACE_ROW_01);
		new_cube._4x4x4_left  = (original_4x4x4_cube._4x4x4_left  & BITMASK_CUBE_FACE_NOT_ROW_01) | (original_4x4x4_cube._4x4x4_front & BITMASK_CUBE_FACE_ROW_01);

		/*********************************************************************************/
		/*                                 Rotate the TOP                                */
		/*********************************************************************************/
		/*                                                                               */
		/* THESE CUBE LOCATIONS BECOME....              THESE CUBE LOCATIONS             */
		/*                                                                               */
		/*                                                                               */
		/*********************************/             /*********************************/
		/*  01   *  02   *  03   *   04  */             /*  13   *  09   *  05   *   01  */
		/*********************************/             /*********************************/
		/*  05   *  06   *  07   *   08  */             /*  14   *  10   *  06   *   02  */
		/*********************************/             /*********************************/
		/*  09   *  10   *  11   *   12  */             /*  15   *  11   *  07   *   03  */
		/*********************************/             /*********************************/
		/*  13   *  14   *  15   *   16  */             /*  16   *  12   *  08   *   04  */
		/*********************************/             /*********************************/
		/*                                                                               */
		/*                                                                               */
		/*********************************************************************************/

		new_cube._4x4x4_top = ((original_4x4x4_cube._4x4x4_top & BITMASK_CUBE_FACE_SQUARE_13) << 48)  | \
							  ((original_4x4x4_cube._4x4x4_top & BITMASK_CUBE_FACE_SQUARE_09) << 28)  | \
							  ((original_4x4x4_cube._4x4x4_top & BITMASK_CUBE_FACE_SQUARE_05) << 8)   | \
							  ((original_4x4x4_cube._4x4x4_top & BITMASK_CUBE_FACE_SQUARE_01) >> 12)  | \
							  ((original_4x4x4_cube._4x4x4_top & BITMASK_CUBE_FACE_SQUARE_14) << 36)  | \
							  ((original_4x4x4_cube._4x4x4_top & BITMASK_CUBE_FACE_SQUARE_10) << 16)  | \
							  ((original_4x4x4_cube._4x4x4_top & BITMASK_CUBE_FACE_SQUARE_06) >> 4)   | \
							  ((original_4x4x4_cube._4x4x4_top & BITMASK_CUBE_FACE_SQUARE_02) >> 24)  | \
							  ((original_4x4x4_cube._4x4x4_top & BITMASK_CUBE_FACE_SQUARE_15) << 24)  | \
							  ((original_4x4x4_cube._4x4x4_top & BITMASK_CUBE_FACE_SQUARE_11) << 4)   | \
							  ((original_4x4x4_cube._4x4x4_top & BITMASK_CUBE_FACE_SQUARE_07) >> 16)  | \
							  ((original_4x4x4_cube._4x4x4_top & BITMASK_CUBE_FACE_SQUARE_03) >> 36)  | \
							  ((original_4x4x4_cube._4x4x4_top & BITMASK_CUBE_FACE_SQUARE_16) << 12)  | \
							  ((original_4x4x4_cube._4x4x4_top & BITMASK_CUBE_FACE_SQUARE_12) >> 8)   | \
							  ((original_4x4x4_cube._4x4x4_top & BITMASK_CUBE_FACE_SQUARE_08) >> 28)  | \
							  ((original_4x4x4_cube._4x4x4_top & BITMASK_CUBE_FACE_SQUARE_04) >> 48);

		return new_cube;
}
```

I just had to create bit "masks" to use as selectors.


```
#define BITMASK_CUBE_FACE_SQUARE_01 0xF000000000000000
#define BITMASK_CUBE_FACE_SQUARE_02 0x0F00000000000000
#define BITMASK_CUBE_FACE_SQUARE_03 0x00F0000000000000
#define BITMASK_CUBE_FACE_SQUARE_04 0x000F000000000000

#define BITMASK_CUBE_FACE_SQUARE_05 0x0000F00000000000
#define BITMASK_CUBE_FACE_SQUARE_06 0x00000F0000000000
#define BITMASK_CUBE_FACE_SQUARE_07 0x000000F000000000
#define BITMASK_CUBE_FACE_SQUARE_08 0x0000000F00000000

#define BITMASK_CUBE_FACE_SQUARE_09 0x00000000F0000000
#define BITMASK_CUBE_FACE_SQUARE_10 0x000000000F000000
#define BITMASK_CUBE_FACE_SQUARE_11 0x0000000000F00000
#define BITMASK_CUBE_FACE_SQUARE_12 0x00000000000F0000

#define BITMASK_CUBE_FACE_SQUARE_13 0x000000000000F000
#define BITMASK_CUBE_FACE_SQUARE_14 0x0000000000000F00
#define BITMASK_CUBE_FACE_SQUARE_15 0x00000000000000F0
#define BITMASK_CUBE_FACE_SQUARE_16 0x000000000000000F

#define BITMASK_CUBE_FACE_ROW_01	0xFFFF000000000000
#define BITMASK_CUBE_FACE_ROW_02	0x0000FFFF00000000
#define BITMASK_CUBE_FACE_ROW_03	0x00000000FFFF0000
#define BITMASK_CUBE_FACE_ROW_04	0x000000000000FFFF

#define BITMASK_CUBE_FACE_NOT_ROW_01 0x0000FFFFFFFFFFFF
#define BITMASK_CUBE_FACE_NOT_ROW_02 0xFFFF0000FFFFFFFF
#define BITMASK_CUBE_FACE_NOT_ROW_03 0xFFFFFFFF0000FFFF
#define BITMASK_CUBE_FACE_NOT_ROW_04 0xFFFFFFFFFFFF0000

#define BITMASK_CUBE_FACE_COL_01     0xF000F000F000F000
#define BITMASK_CUBE_FACE_NOT_COL_01 0x0FFF0FFF0FFF0FFF

#define BITMASK_CUBE_FACE_COL_02     0x0F000F000F000F00
#define BITMASK_CUBE_FACE_NOT_COL_02 0xF0FFF0FFF0FFF0FF

#define BITMASK_CUBE_FACE_COL_03     0x00F000F000F000F0
#define BITMASK_CUBE_FACE_NOT_COL_03 0xFF0FFF0FFF0FFF0F

#define BITMASK_CUBE_FACE_COL_04     0x000F000F000F000F
#define BITMASK_CUBE_FACE_NOT_COL_04 0xFFF0FFF0FFF0FFF0
```

Every "&" in C is a Bit-AND, which is like multiplication in base-2. 1x0 = 0, 1x1 = 1, so when the patterns line up, only those marked with 1 will be passed on. Those marked with 0 are ignored.
Every "|" in C is a Bit-OR, which is like addition without a carry in base-2. 1+0 = 1, 1+1 = 1, 0+0 = 0, so when you see a 1 or a 0, the 1 will be passed on.

0xF000000000000000 in base-16 = 1111 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 in base-2. So when you take a 64-bit cube face, and bit-AND with that pattern, you only get the one cube on the top-left of the 16. If you want all of the cubes on in the top row, bit and with 0xFFFF000000000000. The next row down is 0x0000FFFF00000000 which is "skipping" the first 4, ignoring the last 4x3 bits, and grabbing the bits in between.


----------



## StachuK1992 (Dec 7, 2014)

Stefan said:


> Note, though, that that's an abomination extraordinaire, utterly abusing Python beyond belief
> 
> I rewrote it so it's actually Python (though I kept the non-standard bad indentation):
> http://ideone.com/8tzvWi
> ...



Oh yes, sub-par code should surely never be posted on the internet!
I am such shame for posting code that I wrote years ago in a short foray into a language.

[note that the above is mostly tongue in cheek. I think it's a bit much to call it an 'abomination extraodinaire' (insulting, useless, and non-constructive) but the code is admittedly poor]



unsolved said:


> It is so fast because each side of the 4x4x4 cube is just one 64-bit integer, 4 bits per "sticker," and I use 64-bit shifts, ANDs, and ORs to make moves, instead of using matrix swap operations.



Wow, very neat. Thanks for sharing, but I'd love to see more. (aka. stop teasing and give us some proper source code!)


----------



## unsolved (Dec 7, 2014)

StachuK1992 said:


> Oh yes, sub-par code should surely never be posted on the internet!
> I am such shame for posting code that I wrote years ago in a short foray into a language.
> 
> [note that the above is mostly tongue in cheek. I think it's a bit much to call it an 'abomination extraodinaire' (insulting, useless, and non-constructive) but the code is admittedly poor]
> ...



Try refreshing your browser. You replied when I was still typing.

I didn't mean to hijack the Python thread here, I am looking to learn Python myself. Most of what I typed above is in the *4x4x4 Programming Discussion* thread. I also have links to download the program in that area.

I would still like to see some Python source for a 4x4x4 solver since just reading over it I believe I can learn the syntax. I'd like to make a python version of my program for practice.


----------



## Stefan (Dec 7, 2014)

StachuK1992 said:


> Oh yes, sub-par code should surely never be posted on the internet!
> I am such shame for posting code that I wrote years ago in a short foray into a language.
> 
> [note that the above is mostly tongue in cheek. I think it's a bit much to call it an 'abomination extraodinaire' (insulting, useless, and non-constructive) but the code is admittedly poor]



Well it's not just sub-par, it's really very bad. It has almost nothing to do with Python. It also wasn't just posted, it was given to a beginner to possibly learn from it.

It's like someone asking for help with the cube and seriously being shown how to peel off the stickers.

Sorry if you felt insulted by my over-the-top introductory joke, though I do hope it's useful (by making clear that that program is bad and by perhaps preventing similar programs being posted for education), and I hope my rewritten program as well as the code snippets in my post are constructive.



StachuK1992 said:


> Wow, very neat. Thanks for sharing, but I'd love to see more. (aka. stop teasing and give us some proper source code!)



Ugh, now he posted even more of it here. Can't that stay in his 4x4 solver thread? What is it doing here?



unsolved said:


> I would still like to see some Python source for a 4x4x4 solver



I think it would be quite slow. That's not really a job for Python.

But maybe you'd like to see a 3x3 simulator? Here's one (the program as a whole checks whether two given algorithms have the same effect, someone made a thread about that a while back), though admittedly it's not the most beginner-friendly example:

https://gist.github.com/pochmann/a70e314bbeb954b13ef5


----------



## mark49152 (Dec 7, 2014)

Stefan said:


> Compare it to how it looks when done properly:
> 
> 
> ```
> ...


Or use Perl and make it even neater:


```
handle() foreach @things;
```


----------



## Stefan (Dec 8, 2014)

mark49152 said:


> Or use Perl and make it even neater:
> 
> 
> ```
> ...



You have to say handle(*$_*), no? Which makes it less neat, and longer than Python. But you can shorten "foreach" to just "for". Comparison then:


```
Perl:   handle($_) for @things;
Python: for t in things: handle(t)
```

I'm not sure Perl's is neater, and I don't miss it. Like I said, you could also use comprehensions or map or whatever. That example was just to show not unnecessarily using indices, and as you can see in the rewritten program, I did replace for-loops with comprehension and map. Where I do use a normal for-loop, I actually prefer a normal one over Perl's modifier one (though I acknowledge they and the other modifiers can be good), and then in Perl you'd have the parentheses and curly braces:


```
Perl vs. Python:

for (@things) {
    print($_);
    #domorestuff with $_
}

for t in things:
    print(t)
    #domorestuff with t
```

You could also do this, but it's rather abusive:

```
map(handle, things)
```


----------



## mark49152 (Dec 8, 2014)

Stefan said:


> Well I think you have to say handle($_), no? Which makes it less neat, and longer than Python. But you can shorten "foreach" to just "for".


No because $_ is global. Not that it would be good programming to do it that way of course. In practice I'd pass it explicitly as you suggest (unless writing obtuse code for my own gratification).

I prefer "foreach" for iterating over a set as it better expresses the semantics.


----------



## Stefan (Dec 8, 2014)

mark49152 said:


> No because $_ is global.



Ah, right. But I'm rather *glad* I didn't think of using that


----------



## mark49152 (Dec 8, 2014)

Stefan said:


> Ah, right. But I'm rather *glad* I didn't think of using that [emoji14]


If there's one thing Perl is very well suited for, it's writing awful cryptic code just to prove you can


----------



## Sauce (Dec 8, 2014)

Hey there, I am also learning Python as you are. My recommendation is to make something like a timer, and things that you have suggested in the post. Because you are a beginner, don't start out to complicated, do some research, when you learn more, you could make an artificial intelligence program to make a online Rubik's cube solver!

I hope that helped,


Sauce,


----------



## martinss (Dec 8, 2014)

I learnt Python when I was 8... Someone I know made a program for 2x2x2. It was just making all possible states by doing a random move and add it if it's not already in the file... But this is not finding an optimal solve...


----------



## Rainbow Flash (Dec 9, 2014)

Hey Sauce,

Thanks for the tip...actually yesterday I set out on an adventure to write a program that would predict the outcome of a cube with a certain scramble. For a beginner like me, I think I actually got a lot done. Of course, progress was slow, and there were a few things I didn't understand, so I had to write everything in a very roundabout way. The program hasn't succeeded...yet. I will continue to further my skills in Python until I am more confident of a faster and better way to write the program.

Hey martinss,

Like I said above I tried to make a similar program to that of which you mentioned. I think finding the optimal solve will be lightyears more difficult than just predicting the outcome of a scramble.

Rainbow Flash


----------



## ajayd (Dec 9, 2014)

mark49152 said:


> If there's one thing Perl is very well suited for, it's writing awful cryptic code just to prove you can



May I introduce you to J


----------



## qqwref (Dec 9, 2014)

I did some stuff in a similar language called q for a work internship a while ago. Here's a relatively efficient prime checker (checked 1125899839733759 in 609 ms):

```
isPrime2:{$[x<2;0b;0=x mod 2;x=2;0<>min x mod 1+2*1_til(floor 1+sqrt x)div 2]}
```


----------



## mark49152 (Dec 9, 2014)

ajayd said:


> May I introduce you to J


Oh wow I love it already...


----------



## DeeDubb (Feb 11, 2015)

I'm working on a letter pair memo program for BLD.

So far it will:

Create a notepad file containing AB - XW (deleting all AA, BB, etc...)

If notepad file exists, import that.

Prompt user for how many pairs to memo (x).

Repeat this sequence x number of times
1. randomly select and display a letter pair
2. allow user to add a "hint"for future memorization (this hint would be your memo for that pair, like MJ hint might be Michael Jordan)
3. If user types anything, the hint will be added to the list for that pair and the notepad will be updated
If user types nothing, it will just move on
4. Append the pair onto a string that starts empty (basically loading the entire word pair sequence as the loop goes)

Clear screen and ask user for the answer.

Removes all white spaces from answer, and also capitalize the answer (in case the user doesn't)

Compare answer to the pair string, if correct, display "correct", if not, display "You typed xxxx, it was actually xxxxx"

Simple program. I'm working on getting it into some kind of GUI with buttons, but so far that has been a nightmare. I can't seem to get the loop to wait for a button click (unlike in text, where it can simply prompt the user to pause the loop).

I also want to add a timer, but that's down the road.


----------



## JemFish (Feb 11, 2015)

DeeDubb said:


> I'm working on a letter pair memo program for BLD.
> 
> So far it will:
> 
> ...



Hey, this is a good idea. Start a thread about it once your done! I'll try making a version too, although I'm not good at any GUI stuff.


----------



## Stefan (Feb 11, 2015)

DeeDubb said:


> I'm working on getting it into some kind of GUI with buttons, but so far that has been a nightmare. I can't seem to get the loop to wait for a button click (unlike in text, where it can simply prompt the user to pause the loop).



Sounds like you're doing it wrong. Typically you build the GUI, register actions that will be called when something happens (like a button click), and then call the GUI's mainloop, i.e., giving up control, not still running your own loop. What GUI package are you using?


----------



## Seanliu (Feb 11, 2015)

DeeDubb said:


> I also learned a little Python in college. It's a *super fun programming language!*
> 
> Honestly, as a beginning programmer, you probably won't be able to make anything that someone already hasn't done, but that shouldn't stop you from playing around with things.
> 
> ...



I <3 Python. Also, for intermediate, wouldn't the time module just make it easy?


----------



## googlebleh (Feb 11, 2015)

Seanliu said:


> I <3 Python. Also, for intermediate, wouldn't the time module just make it easy?



I also heart Python. And for most problems, there is always a module you can use to "make it easy." But I'm not so sure timing is one of them. Python's time module is questionable. Some people say it's supposed to be accurate, others think it's not so great.

Some time ago, I wrote a megaminx simulator in Python, but after testing its time module against whatever qqTimer uses, I found that my timer slowly became farther and farther off. It could be because of all the work it was doing simultaneously to render the megaminx, or whatever, but depending on what you're writing (and the duration you want to measure) I would not say that it's that simple of a problem.


----------



## Stefan (Feb 11, 2015)

I think if you're not doing it wrong, timing is both simple and accurate.


----------



## Seanliu (Feb 12, 2015)

The problem: Python measures in seconds. So inacurrate.


----------



## DeeDubb (Feb 12, 2015)

Stefan said:


> Sounds like you're doing it wrong. Typically you build the GUI, register actions that will be called when something happens (like a button click), and then call the GUI's mainloop, i.e., giving up control, not still running your own loop. What GUI package are you using?



I'm using Tkinter for the GUI. I'm sure there's a way to use it, I just never learned it.

Basically, here's what I want:

While x is lower than (Total Pairs to Memo):
Randomly select and display a pair
(pause and wait for feedback)
Either they can add a hint, or simply press enter to continue (so enter triggers the next pair, the hint won't trigger it, I can do that part easily).


I don't know HOW I can force the loop to wait for the enter.

Right now, I have it functioning in a non-GUI loop. I may have to build it into the GUI mainloop instead?


----------



## Jakube (Feb 12, 2015)

Seanliu said:


> The problem: Python measures in seconds. So inacurrate.



No, which commands are you using?


```
import time
t1 = time.time()
#do some stuff
t2 = time.time()
print(t2-t1)
```


----------



## Stefan (Feb 12, 2015)

DeeDubb said:


> I may have to build it into the GUI mainloop instead?



I guess you could say it that way. I don't think about the mainloop, though. I just think of sitting there are reacting to events. Like, when I'm told that the button got clicked, I change my data and the gui accordingly. Then wait for the next event. Did you go through some tkinter tutorial(s) yet?


----------



## Stefan (Feb 12, 2015)

Seanliu said:


> The problem: Python measures in seconds. So inacurrate.



It uses seconds as unit, but with floating point values. Here's a little test:


```
Output:

    1157322 different times recorded in a 1 second interval
    The last ten:
    0.99999237 seconds
    0.99999309 seconds
    0.99999404 seconds
    0.99999475 seconds
    0.99999547 seconds
    0.99999642 seconds
    0.99999714 seconds
    0.99999809 seconds
    0.99999881 seconds
    0.99999976 seconds

Program:

    from time import time
    times = [time()]
    while True:
        t = time()
        if t > times[-1]:
            if t - times[0] > 1:
                break
            times.append(t)
    print(len(times), 'different times recorded in a 1 second interval')
    print('The last ten:')
    for t in times[-10:]:
        print('%.8f seconds' % (t - times[0]))
```


----------



## AlphaSheep (Feb 12, 2015)

DeeDubb said:


> I'm using Tkinter for the GUI.



I have a little experience with Tkinter, but I really don't like it. I much prefer PyQt for GUI stuff these days because I find it's both easier to use and more powerful.

Anyway, since you're already using Tkinter, what you need to do is this. Put all the stuff to do into a function, (I'll call it someFunction here, but please give it a better name). Then somewhere in your program before you call root.mainloop(), add the following line:

```
root.bind('<Return>', lambda event: someFunction())
```

Then whenever the user presses Enter, the program will call someFunction. The lambda bit is just there because bind wants to send event information to the function, but your function won't use that information, so the lambda bit just causes the event information to be left from the function call.

I hope that helps you.


----------



## Stefan (Feb 12, 2015)

Timing update: Sweet, I might have found my clock speed, looks like 4 Mhz. I recorded a million times, and there were duplicates, indicating my new program is faster than the clock. After removing the duplicates, I saw that the times are 1/4194304 of a second apart, and that's *exactly* 2[sup]-22[/sup].


```
Output:

    781175 different times recorded in 0.213952 seconds
    The last ten:
    0.21394968 seconds (step: 1/4194304)
    0.21394992 seconds (step: 1/4194304)
    0.21395016 seconds (step: 1/4194304)
    0.21395040 seconds (step: 1/4194304)
    0.21395063 seconds (step: 1/4194304)
    0.21395087 seconds (step: 1/4194304)
    0.21395111 seconds (step: 1/4194304)
    0.21395135 seconds (step: 1/4194304)
    0.21395159 seconds (step: 1/4194304)
    0.21395183 seconds (step: 1/4194304)
    2 ** 22 = 4194304

Program:

    from time import time
    times = sorted(set([time() for _ in range(1000000)]))
    print(len(times), 'different times recorded in %f seconds' % (times[-1] - times[0]))
    print('The last ten:')
    for i in range(-10, 0):
        print('%.8f seconds (step: 1/%d)' % (times[i] - times[0], 1 / (times[i] - times[i-1])))
    print('2 ** 22 =', 2 ** 22)
```


----------



## rokicki (Feb 12, 2015)

Very funny, Stefan.

The magic number here is 53, as in 53 bits.



Stefan said:


> Timing update: Sweet, I might have found my clock speed, looks like 4 Mhz. I recorded a million times, and there were duplicates, indicating my new program is faster than the clock. After removing the duplicates, I saw that the times are 1/4194304 of a second apart, and that's *exactly* 2[sup]-22[/sup].


----------



## DeeDubb (Feb 12, 2015)

AlphaSheep said:


> ```
> root.bind('<Return>', lambda event: someFunction())
> ```
> 
> ...



I did get that part, so I can trigger a function when I press enter, but the problem is my current while loop uses an input prompt to "pause" and wait for input (using x = raw_input) This is an easy cheap way to pause a loop. however, it seems I can't do that with stuff that's passive on the GUI (enter key or pressing a button). 

The solution I was thinking of was having a global variable that counts up to how many rounds of letter pairs, and rather than using a while loop, just use a function that is triggered when someone presses enter. However, this would have to be nullified when the game isn't running (I suppose counting down to zero would be better, and when the global is zero, don't run the game stuff).

Here's my functioning code without the GUI (Python 3.x)


```
import random
import os

#Z = 90
#A = 64

#main function. This should be run automatically at some point
def runGame():
    #checks to see if the letterList text file already exists
    fileCheck = os.path.isfile("letterList.txt")

    #if the file exists, process the file, if not create a new file
    if (fileCheck == True):
        letterList = processFile()
    else:
        letterList = createTable()    
    
    listLength = len(letterList)
    print ("How many pairs would you like to memorize?")
    
    ## TO ADD: ensure that input is a number
    pairCount = int(input())

    #runs the game
    letterList = playIt(pairCount,letterList)
    

#this is the 'game' portion
def playIt(pairCount,letterList):
    ## TO ADD: timer to run
    answer = ""

    #runs the current round until the requested pair count
    for current in range(0, pairCount):
        #random number between 0 and the length of the list
        roundRand = random.randint(0,len(letterList))

        #calls the pair associated with that random number
        pair = letterList[roundRand][0]
        print(pair)

        #displays the hints for the current pair, if they exist
        #TO ADD: Make some settings to make this optional
        for x in range (1, len(letterList[roundRand])):
            print ("Hint " + str(x) + ": " + letterList[roundRand][x])

        #keeps a string containing all of the pairs
        answer += pair
        
        #user can choose to add a hint for future runs, or just proceed
        print ("Type to add a new hint or press Enter to proceed")
        hint = input()
        
        letterList = addHint(letterList, hint, roundRand)
    print ("Type the letter sequence")
    userAnswer = input()
    
    #TO ADD: clear the shell
    os.system('cls' if os.name == 'nt' else 'clear')

    #no longer case sensitive, and takes out spaces
    userAnswer = userAnswer.upper()
    userAnswer = userAnswer.replace(" ", "")

    if (answer == userAnswer):
        print ("Congratulations! You got it right!")
    else:
        print ("Sorry, the answer was " + answer + ", but you typed " + userAnswer + ".")
    return letterList

#function adds a hint element. This can be done an unlimited number of times, so each pair can have multiple hints
def addHint(letterList, hint, roundRand):
    if (hint != ""):
        letterList[roundRand].append(hint)
    writeFile(letterList)
    return letterList
    


def createTable():
    letterList = []
    #shift to the upper case letter index
    shift = 65

    #runs through the first letter
    for firstLet in range(0, 24):
        #nexted for loop to pair the first letter with a second letter
        for secondLet in range(0,24):
            #if statement ensure no double same letter pairs (i.e. "AA")
            if (firstLet != secondLet):
                letPair = (chr(firstLet+shift)+chr(secondLet+shift))
                #appends a list so more information can be added to a letter pair
                letterList.append([letPair])
    writeFile(letterList)
    return letterList


def writeFile(letterList):
    file = open("letterList.txt", "w")
    for line in range(0, len(letterList)):
        for element in range(0, len(letterList[line])):
            file.write(letterList[line][element])
            #adds a ", " if it's not the final element of the list
            if (element+1 < len(letterList[line])):
                file.write(", ")
        file.write("\n")
    file.close()

def processFile():
    letterList = []
    #loads the file into a list of the lines
    with open("letterList.txt") as f:
        lines = f.readlines()
    #runs each line, cutting off the line break, and splitting by the comma space.
    for line in range(0, len(lines)):
        raw = lines[line].rstrip()
        rawList = raw.split(", ")
        letterList.append(rawList)
    return letterList
```


----------



## Stefan (Feb 12, 2015)

rokicki said:


> Very funny, Stefan.
> 
> The magic number here is 53, as in 53 bits.



Darn, does that mean 12 years ago I would've gotten twice the resolution I got now? Is my computer getting worse?


----------



## rokicki (Feb 13, 2015)

Stefan said:


> Darn, does that mean 12 years ago I would've gotten twice the resolution I got now? Is my computer getting worse?



You probably wouldn't have 12 years ago, but if you tell your computer it is
12 years ago, you may get twice the resolution now. Let's repeat the
experiment in 23 years and see what happens; maybe you'll get even less
resolution then.


----------



## Stefan (Feb 13, 2015)

rokicki said:


> You probably wouldn't have 12 years ago, but if you tell your computer it is
> 12 years ago, you may get twice the resolution now.



Oh right. I just tried it and it kinda worked  (I say "kinda" because now my program's speed is the bottleneck and it gets the double resolution only occasionally)

Do you know how to find out the real resolution? Or is it just my CPU speed, e.g., 1.6 GHz? I vaguely remember playing with the system clock in assembler in the 1990s and thought it's separate from the CPU, but I have no idea about today and couldn't find anything.

I tried again in Go, as that's faster and offers nanoseconds as integer. I get around 16.8 million distinct times per second and no duplicates, so apparently the program is the bottleneck and the clock is still faster.


```
10000000 distinct times in 593.95314ms
16.836345 million distinct times per second
```



Spoiler: Program





```
package main

import (
	"fmt"
	"time"
)

func main() {
	t0 := time.Now()
	t := t0.Nanosecond()
	ctr := 0
	for i := 0; i < 10000000; i++ {
		tmp := time.Now().Nanosecond()
		if tmp != t {
			t = tmp
			ctr++
		}
	}
	elapsed := time.Since(t0)
	fmt.Println(ctr, "distinct times in", elapsed)
	fmt.Printf("%.6f million distinct times per second\n", float64(ctr)/elapsed.Seconds()/1000000)
}
```


----------



## DeeDubb (Feb 13, 2015)

AlphaSheep said:


> I have a little experience with Tkinter, but I really don't like it. I much prefer PyQt for GUI stuff these days because I find it's both easier to use and more powerful.
> 
> Anyway, since you're already using Tkinter, what you need to do is this. Put all the stuff to do into a function, (I'll call it someFunction here, but please give it a better name). Then somewhere in your program before you call root.mainloop(), add the following line:
> 
> ...



I'm reading this more, and trying to figure it out. I'm wondering if I could do this in a recursive loop, where it starts with x = how many pairs, runs through the function and every time enter is pressed, it lowers x by 1 until it hits zero where the function will no longer work.


----------



## DeeDubb (Feb 13, 2015)

Ugh, so I'm trying to call a variable from a different function. I know that's kind of like a "global variable" and those are evil, apprently, but I have one function establishing my GUI, and then I want other functions to be able to modify lables on my GUI. This won't work with calls and returns, because the functions need to be activated by buttons in the GUI, and buttons don't have a return, as far as I know.


----------



## AlphaSheep (Feb 13, 2015)

It's a simple program. Just use the global variables...

Yes, global variables are evil, and you should avoid them in general, but the whole philosophy of python is to keep it simple and not overcomplicate matters. The better approach would be to use OOP and have your functions manipulate the attributes of objects. Then you'd only have to pass objects to functions, and the functions wouldn't need to return anything. But since your program is going to probably be a single file of a couple hundred lines, that's a lot of extra effort and complication just to avoid using global variables.


----------



## DeeDubb (Feb 13, 2015)

AlphaSheep said:


> It's a simple program. Just use the global variables...
> 
> Yes, global variables are evil, and you should avoid them in general, but the whole philosophy of python is to keep it simple and not overcomplicate matters. The better approach would be to use OOP and have your functions manipulate the attributes of objects. Then you'd only have to pass objects to functions, and the functions wouldn't need to return anything. But since your program is going to probably be a single file of a couple hundred lines, that's a lot of extra effort and complication just to avoid using global variables.



I'm starting to figure out classes, I'm rewriting the program to fit in that environment. It's actually working pretty well. Thanks for your help!


----------



## DeeDubb (Feb 13, 2015)

I finished! I just need to get the layout looking a bit nicer, but it seems to be fully functional and not too breakable. Feel free to try out my code, and let me know how it works for you. (It creates a notepad in the same folder it's in, so make sure you can keep track of that).


```
from tkinter import *
import random
import os

class Application(Frame):

    def __init__(self, master):

        Frame.__init__(self,master)
        self.grid()
        self.create_widgets()
        self.variables()
        self.letterListGrab()
        root.bind('<Return>', self.rounds)
        self.countdown()
        


    def countdown(self):
        if (self.timerStart == True):
            self.label.configure(text= round(self.remaining, 2))
            self.remaining = self.remaining + .01
        self.after(10, self.countdown)
            
    def create_widgets(self):
        self.pair = Label(self, text="Helvetica", font=("Helvetica", 30))
        self.pair["text"] = " "
        self.pair.grid(row=0, column=0, columnspan=3, pady=30, padx=30)

        self.hintLab = Label(self)
        self.hintLab["text"] = ""
        self.hintLab.grid(row=1, columnspan=3)

        self.instr0 = Label(self)
        self.instr0["text"] = "How many pairs would you like to memorize:"
        self.instr0.grid(row=2, column=0, columnspan=3)
     
        self.countEntry = Entry(self)
        self.countEntry["text"] = "5"
        self.countEntry.grid(row=3, column=0, columnspan=2)

        self.start = Button(self)
        self.start["text"] = "Start"
        self.start["command"] = self.runGame
        self.start.grid(row=3, column=2)
        
        self.result = Label(self, wraplength=280)
        self.result["text"] = ""
        self.result.grid(row=4, column=0, columnspan=3)
        
        self.label = Label(self, text="Helvetica", font=("Helvetica", 20))
        self.label["text"] = "0.00"
        self.label.grid(row=5, columnspan=3, pady=30, padx=30)



    def variables(self):
        self.pairCount = 5
        self.tally = 0
        self.answer = ""
        self.remaining = 0.0
        self.timerStart = False

    def runGame(self):
        self.timerStart = True
        
        self.pairCount = int(self.countEntry.get())

        self.instr0.destroy()
        self.start.destroy()
        self.countEntry.destroy()

        self.instr1 = Label(self)
        self.instr1["text"] = "Press Enter to Continue"
        self.instr1.grid(row=2, column=0, columnspan=3)

        self.hintry = Entry(self)
        self.hintry["text"] = ""
        self.hintry.grid(row=3, column=0, columnspan=2)

        self.hintSub = Button(self)
        self.hintSub["text"] = "Add Hint"
        self.hintSub["command"] = self.addHint
        self.hintSub.grid(row=3, column=2)


        self.hintLab["text"] = ""
        self.pairNum = randPair(self.letterList)
        self.curPair = str(self.letterList[self.pairNum][0])
        self.answer += self.curPair
        self.pair["text"] = self.curPair
        for x in range (1, len(self.letterList[self.pairNum])):
            self.hintLab["text"] = "Hint " + str(x) + ": " + self.letterList[self.pairNum][x]
        self.tally += 1

    def rounds(self, event):
        self.hintLab["text"] = ""
        if (self.tally == 0):
            return  
        elif (self.tally < self.pairCount):
            self.pairNum = randPair(self.letterList)
            self.curPair = str(self.letterList[self.pairNum][0])
            self.answer += self.curPair
            self.pair["text"] = self.curPair
            for x in range (1, len(self.letterList[self.pairNum])):
                self.hintLab["text"] += "Hint " + str(x) + ": " + self.letterList[self.pairNum][x] + "\n"
            self.tally += 1
        elif (self.tally == self.pairCount):
            self.checkAnswer()
            self.tally += 1
        else:
            return
        
    def checkAnswer(self):
        self.start.destroy()
        self.pair["text"] = " "
        self.instr1.destroy()
        self.hintry.destroy()
        self.hintSub.destroy()

        self.ansPrompt = Label(self)
        self.ansPrompt["text"] = "Type in the answer:"
        self.ansPrompt.grid(row=2, column=0, columnspan=3)

        self.ansEntry = Entry(self)
        self.ansEntry["text"] = ""
        self.ansEntry.grid(row=3, column=0, columnspan=2)

        self.submit = Button(self)
        self.submit["text"] = "Submit"
        self.submit["command"] = self.compare
        self.submit.grid(row=3, column=2)    
        

    def compare(self):


        
        self.totPairs = int(len(self.answer)/2)
        self.timerStart = False
        self.userAnswer = self.ansEntry.get()
        self.userAnswer = self.userAnswer.upper()
        self.userAnswer = self.userAnswer.replace(" ", "")

        self.ansPrompt.destroy()
        self.ansEntry.destroy()
        self.submit.destroy()
        self.resetBut = Button(self)
        self.resetBut["text"] = "Reset"
        self.resetBut["command"] = self.reset
        self.resetBut.grid(row=3, column=2)
        
        if (self.userAnswer == self.answer):
           self.result["text"] = "Congratulations! You memorized " + str(self.totPairs) + " pairs."
        else:
            self.result["text"] = "Sorry, the answer was " + self.answer + ", but you typed " + self.userAnswer + "."

        self.submit.destroy()

        
    
    def reset(self):
        self.destroy()
        Application(root)
            

    def letterListGrab(self):
        #checks to see if the letterList text file already exists
        fileCheck = os.path.isfile("letterList.txt")

        #if the file exists, process the file, if not create a new file
        if (fileCheck == True):
            self.letterList = processFile()
        else:
            self.letterList = createTable()

    def addHint(self):
        self.addHint = str(self.hintry.get())
        if (self.addHint != ""):
            self.letterList[self.pairNum].append(self.addHint)
            writeFile(self.letterList)       

def randPair(letterList):
    roundRand = random.randint(0,len(letterList))
    return roundRand


def createTable():
    letterList = []
    #shift to the upper case letter index
    shift = 65

    #runs through the first letter
    for firstLet in range(0, 24):
        #nexted for loop to pair the first letter with a second letter
        for secondLet in range(0,24):
            #if statement ensure no double same letter pairs (i.e. "AA")
            if (firstLet != secondLet):
                letPair = (chr(firstLet+shift)+chr(secondLet+shift))
                #appends a list so more information can be added to a letter pair
                letterList.append([letPair])
    writeFile(letterList)
    return letterList


def writeFile(letterList):
    file = open("letterList.txt", "w")
    for line in range(0, len(letterList)):
        for element in range(0, len(letterList[line])):
            file.write(letterList[line][element])
            #adds a ", " if it's not the final element of the list
            if (element+1 < len(letterList[line])):
                file.write(", ")
        file.write("\n")
    file.close()

def processFile():
    letterList = []
    #loads the file into a list of the lines
    with open("letterList.txt") as f:
        lines = f.readlines()
    #runs each line, cutting off the line break, and splitting by the comma space.
    for line in range(0, len(lines)):
        raw = lines[line].rstrip()
        rawList = raw.split(", ")
        letterList.append(rawList)
    return letterList


root = Tk()
root.title("Letter Pair Game")
root.geometry("300x300")

app = Application(root)

root.mainloop()
```


----------



## Stefan (Feb 13, 2015)

I shouldn't have looked... now my hate for unpythonic Python kicked in . I'll leave it at this bit, though.


```
def createTable():
    letters = "ABCDEFGHIJKLMNOPQRSTUVWX"
    letterList = [[first + second]
                  for first in letters for second in letters
                  if first != second]
    writeFile(letterList)
    return letterList


def writeFile(letterList):
    with open("letterList.txt", "w") as file:
        for line in letterList:
            print(", ".join(line), file=file)
```


----------



## DeeDubb (Feb 13, 2015)

Stefan said:


> I shouldn't have looked... now my hate for unpythonic Python kicked in. I'll leave it at this bit, though.
> 
> 
> ```
> ...



Thanks for the help. I'm not a CS major, so this is purely just a hobby that I'm learning on the fly.

Most of the stuff I've done is javascript, but I do enjoy Python.


----------

