March 30, 2015

Week of 03/22/15 - Python Part 24: Writing Interruption

    On Tuesday, March 24, I could not work on my Python project very much because we had to do a writing piece for the State of Texas. It was supposed to be a hypothetical submission for an art demo. I couldn't really think of what it should be, until my friend reminded me about my use of ASCII art in my project. That gave me the idea of an ASCII animation, and I would use Python to display it. I would convert each frame of a video of a bouncing ball through a conversion program, then save each ASCII frame in a separate text file. Then, using Python, I would open the first frame's file, display it, wait 1/30th of a second, clear the terminal, then show the next one. I would also make it loop. This got me thinking about my use of ASCII in my own Python code. So, instead of cluttering up my code with a bunch of print() statements, I put the ASCII art in a separate text file, and actually wrote the code to display it in both the test file and the main file.

    Next thing I tried to do was make a distinction using html of the post before this one. The original html showed two areas of code where one was an iteration of the other. To show the difference between the two pieces of code, I changed the different part's background color to maroon using another set of <pre> tags. However, apparently the pre tag makes a new paragraph when used, making a space which I don't want there. To fix this, I did some googling and learned how to do it in CSS. But I can't really change the CSS in Blogger, so that's when I learned I could input CSS using html with the <style> tag. Now it looks like this:


March 24, 2015

Week of 03/08/15 - Python Part 23: Adding Nothing

    What I've done now is I have created a new file, a test file, to check if the checker works like it should, because I haven't tested it yet. I just made some variables, and used a board that was already filled in with a winning combination,row and board variables that made sense, and a player number. Now, the first problem I ran into when I ran the test for the first time was that for the diagonal checking functions, they had to have two conditions that were true in order for the function to return a 1, and if they weren't it would return a zero. The code read:
    def diag_bl_tr_checker(row, column, board):
        if row == column:
            if board[0][0] == board[1][1] == board[2][2]:
                return 1
            else:
                return 0

    The problem with the code is the first if statement, which checks if the row is equal to the column, and this was also a problem with the other function, which checked if the row added to the column equaled 2. If the first if statement evaluated to false, the code wouldn't return anything, and its addition into the flag_number variable wouldn't work because it was not a number, so it gave an error.
      flag_number =   column_checker(column, board)
                    + row_checker(row, board)
                    + diag_bl_tr_checker(row, column, board)
                    + diag_tl_br_checker(row, column, board)
    Now, the code has an else statement that returns zero at the end, so now it works.

    def diag_bl_tr_checker(row, column, board):
        if row == column:
            if board[0][0] == board[1][1] == board[2][2]:
                return 1
            else:
                return 0
        else:
            return 0

March 9, 2015

Week of 03/01/15 - Python Part 22: Rewrite

    To fix the issue outlined in last week's post, what I first did was remove each checker from the if statement, and put each checker into it's own function. I also made the function return zero if there are no wins on the board. Then, I removed their ability to distinguish between player, because this checker checks the board after the player places their piece, so the player_number variable should be sufficient for the new checker function. Now what the individual checking functions do is they each return whether or not they evaluate to true, and if so, they return a 1. If it's not, the function will evaluate to 0. I could have used a true or false, but those wouldn't be able to be manipulated in the way I need to.
    def column_checker(column, board):
        if board[0][column] == board[1][column] == board[2][column]:
            return 1
        else:
            return 0

    Now, all of the functions that were written look like the one shown above. Then, for the actual checking function, I add them all up and see if the resulting number is greater than or equal to 1, at which point the game will say congratulations and then it will end. I have also decided to make a little easter egg where if the player gets more than 1 three-in-a-row at the same time, it would print ASCII art to the terminal. I wouldn't make it myself because I don't know how, so I'll find some on the internet.

February 27, 2015

Week of 02/22/15 - Python Part 21: Finding a Solution

    As we all know, alcohol is a solution. However that's not the kind of solution I'm looking for. What I think I can do to see what the problem is, is printing out the row and column variables after they are set, using the print(row) and print(column) functions. From doing this, I found out that the coordinates of the bottom-left to top-right are (0,2), (1,1), and (2,0). These are the expected values that were discussed in last week's post. So, in theory, this code:
    elif (row + column) == 2:
        if board[0][2] == board[1][1] == board[2][0]:
            if board[0][2] == " X ":
                return 1
            elif board[0][2] == " O ":
                return 2
should work. But, for some reason it doesn't. I don't see any problems with the syntax. But now that I've mulled it over, I see something that may cause me a headache down the line: what if both diagonals are completed at the same time? But then i realized that this was a non-issue because it would choose the one that was further up the elif statement tree. This is also the case with the normal edges. Maybe later I should congratulate the player if he gets a double. But that would take some rewriting of my checking function. But, I think re-writing my checking function would be a good idea anyway, because I have no idea why the other diagonal isn't working. Maybe it's because they share an entry, (1,1). In any case, this problem can probably be solved by rewriting the logic behind the checker.

    To fix the issue I'm having, what I think I'll do is related to something that I saw on reddit a few weeks ago. There was a bug in the game "Team Fortress 2", where sentry guns (automatic turrets) could be exploited to turn back on during a humiliation round, a gamemode after a normal round where the members of the losing team can't fight back, just move around. In the humiliation round the sentry guns of the losing team get disabled. However, the exploit is that if, before the humiliation round, the sentry begins upgrading (which disables the sentry) and when it's done upgrading, the sentry comes back on even though the humiliation round should have disabled them.
    The guy on reddit said "I suspect the sentry has a single flag which is set when it is disabled. For example, by a sapper, by humiliation period, by a building animation, or by soldier lasers. The problem is that these conditions can occur simultaneously." So when the sapper is removed, the game still uses the function to restore the sentry at the end, even though there's another condition which should have kept the sentry disabled. The guy on reddit said that you need to set a separate flag for each condition, so that's what I'm going to do; 1 flag for a horizontal or vertical win, and 1 flag for the diagonals. Unless I want to put in and easter egg for getting 2 wins at the same time. In which case, I would have to make a flag for each: vertical, horizontal, and 2 diagonals. I thought about writing a class for it, but that seems unnecessarily difficult. So what I'm going to do is write a new checker.

February 19, 2015

Week of 02/15/15 - Python Part 20: Debugging

    I have found a bug in my code. The problem is that, when the diagonal, starting from the bottom left and ending in the top right, is completed, the game doesn't register it as a win. For example:

    Turn # 9
       [1] [2] [3]
     1    | X | O 
       -----------
     2  X | O | X 
       -----------
     3  O | X | O 
    Player 1: Enter the column number of your move:

    Even though the bottom-left to top-right diagonal is completed, the game doesn't recognize it. The other diagonal is recognized, and so are the other rows and columns. Now, let's look at the code behind the checker function:

    elif (row + column) == 2:
        if board[0][2] == board[1][1] == board[2][0]:
            if board[0][2] == " X ":
                return 1
            elif board[0][2] == " O ":
                return 2
(I have colored the background of the code blue to signify that this is code, not terminal output.)

    First, I must explain that in order for the board to work, 1 is subtracted from both the row and the column in order to make the row and column numbers correspond with their list entry. With that out of the way,  how my code checks for a win is: after checking the column the move was in, and the row the move was in, it checks if the column was equal to the row. Because the row can only equal the column on a single diagonal, from the top-left to the bottom-right, it checks if those three are equal to each other. Then, after that, the code above checks if the column added to the row is equal to 2 because the (row,column) combinations that are on that diagonal are (0,2), (1,1), and (2,0) and when you add each (row,column) pair you get 2 for each. Then it checks if they're all equal, and then it decides whether to return a 1 or a 2 depending on who's move was in the diagonal. In theory, this should work. In practice, it does not. It just goes to the next turn. Which it shouldn't. I suspect the problem to be in the first line, elif (row + column) == 2:, because the rest of the code is being used in the other elif statements.

February 17, 2015

Week of 02/08/15 - Python Part 19: Lots of Work was Done

     Usually, I don't really do a lot of work in Independent Study. But this week is quite the exception. What I did was finish a game-checking script, so after every move, it checks the entire row, column, and if the move was on one of the diagonals, it would check the diagonals. I got this idea after reading some forums, and figured it would be a great alternative to checking each and every row, column, and diagonal every turn. The checker took a lot of work to write, with me having to define what should happen if player 1 wins or if player 2 wins. Also, instead of putting the checker() function inside of the turn() function, I decided to put the checker function as part of the for-loop instead, and made it so that the checker function only runs when the for-loop reaches 5 or more loops. To do this, I also had to move the variables row and column from the turn function, and made it go from:
def turn(i, playing):        
    Column=0                 
    Row=0                    
    (More code here)         

for i in range(1,10):        
    turn(i, playing)         

To:
for i in range(1,10):
    column = 0
    row = 0
    turn(i, playing, column, row)
    if i >= 5:
        checked = checker(i, playing, column, row, board)

    Next what I did was I combine the two files, main.py and definitions.py. I did this partially because I was having some issues with imported functions not working right, and because I thought it would be easier to debug than two separate files. This came with some renaming and restructuring of the combined file. I also accidentally saved the file to two different directories, but I used the unix command, diff, to figure out which was newer.

February 10, 2015

Week of 02/01/15 - Python Part 18: Problem

     Recently, codingground has been very finicky. I open up it's website, click on "python-3", and instead of redirecting me to it's Python 3 interpreter and IDE, it just refreshes the page and doesn't do anything. And just, now it started working again. I can't handle the fact that sometimes it just doesn't work. Therefore, I'm looking around for a different online interpreter. I was looking at codeanywhere, but after some careful reading, I learned that using it for free was only a week-long trial. I settled on koding, but first I need to figure out how to use it. It seems to me that koding is a virtual machine with a http server, but all I need to use it for is as an executor of python code.

     So what have I done so far on koding? Well, for starters, I finally got the turn number to increment, using the variable used in the for-loop. It used to look like this, with the incrementer (turn_number += 1) being in the turn() function.
if AI_choice == "1":
    turn_number = 0
    for i in range(1,10):
        turn(turn_number, playing)
     But then, I thought that maybe it wasn't incrementing due to a problem with the variable itself. So I decided to try using the variable I used to make the loop, i, in the turn() function itself:
if AI_choice == "1":
    for i in range(1,10):
        turn(i, playing)

    I would post more this week, but on Friday I looked for more html stuff to make my website better. Specifically, I made it so the positioning of my code in the pre tag was centered, so that it looked nicer. Then, on an older post, number 15, I screwed around with the html until I centered the example of the tic-tac-toe board. I learned about html positioning, including absolute and relative positioning.