-2

I am trying to write a Sudoku game with user input. So the user can choose what row/column it wants to and what number. I have to import it from a text file and have made a save and load function.

I have tried starting with what I know, but I don't know how to proceed, ex. how to make the board correspond with the user input.

sudoku_brett.txt

    0 1 2   3 4 5   6 7 8 
  +-------+-------+-------+
0 | 0 0 6 | 9 0 5 | 0 1 0 |
1 | 9 7 0 | 0 1 2 | 3 0 5 |
2 | 0 2 0 | 0 0 4 | 8 6 0 |
  +-------+-------+-------+
3 | 5 0 3 | 8 0 0 | 0 2 0 |
4 | 0 0 0 | 0 0 0 | 0 0 0 |
5 | 0 8 0 | 0 0 1 | 9 0 7 |
  +-------+-------+-------+
6 | 0 5 4 | 1 0 0 | 0 7 0 |
7 | 2 0 7 | 4 5 0 | 0 9 3 |
8 | 0 6 0 | 7 0 3 | 1 0 0 |
  +-------+-------+-------+

main code

import save_load
import info
import sudoku_brett

print("Velkommen til sudoku, dette er brettet ditt" readFromFile('sudoku_brett.txt')) #giving them an importet board

print("Vil du gjøre endringer på brettet?") #asking what changes the user wants to make

col = int(input('Hvilken kolonne vil du endre? ')) #changing column
row = int(input('Hvilken rad vil du endre? ')) #changing row
nytt_tall = int(input('Hva skal det nye tallet være? ')) #asking what number the user would like

brett[row - 1][col - 1] = nytt_tall

print('Ditt nye brett:\n') #printing out the board, with the new input number

bruker.print_board(sudoku_brett)

info.py

def check_input(user_input):
    if user_input.isdigit():
        if 1 <= int(user_input) <= 9:
            return True
    print ("Det kan kun være tall mellom 1-9. Prøv igjen") #telling it can only be number from 1-9
    return False

def print_board(board):
    for row in board:
        print(row)

def generate_empty_board():
    return [[[[0 for i in range(3)] for i in range(3)] for i in range(3)] for i in range(3)]


print_board(generate_empty_board())

save_load.py

 def readFromFile(filename):
    f = open(filename,'r')
    innhold = f.read()
    print(innhold)
    f.close()

def save(filename, board):
    f = open(filename, 'sudoku_brett')
    pickle.dump(board, f)
    f.close()
    print("Brett lagret") #saved

def load(filename):
    f = open(filename, 'sudoku_brett')
    board = sudoku_brett(f)
    f.close()
    print("Brett lastet") #loaded
    return board
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459

3 Answers3

0

I would recommend trying to use the module pygame. If you look into it(here are the docs), it probably has a method to use. It is a module designed to make games. It is typically used to create a window and play the game in the window though, so I'm not 100% sure how you could make it apply. But it is worth a shot. I can't think of another way.

Pygame has mouse location/click detection and key press detection, so both methods of input can be implemented I'm just not sure how in the terminal, only in a game window.


In order to detect key presses in pygame, here is what you can do. I would recommend(if your terminal supports it) highlighting a character that is selected, then moving that selection around. Here is how to add colored text to terminal.

import pygame

# all of your code here, or however you want to format it

pygame.init() # initialize pygame
FPS = 60
clock = pygame.time.Clock() # create a clock
running = True 
while running: # create an infinite loop
    clock.tick(FPS) # only allow this loop to run FPS times per second, just standardizes game speed
    for event in pygame.event.get(): # checks for any input events
        if event.type == pygame.KEYUP: # if event is lifting a key(prevents from multiple inputs by holding down a key)
            if event.key == pygame.K_UP: # if key is up arrow
                move_selected_up() # function to move selected cell up
            if event.key == pygame.K_w: # if key is w
                move_selected_up()

If you are doing this though, I would also reccomend adding a function to break the loop when they finish playing, and you can do saves with key presses. Here are the codes for K_ if you want to use any key.

  • thanks, I will check it out! But I was trying to make it work using the terminal, hmm – confusedstudent Oct 30 '21 at 11:12
  • You can make it work in the terminal still but it will be with key presses. Maybe if you can design some cell highlighting method, then use arrow keys to move around and your selected one is highlighted, then press 1-9 to input a number? Just some ideas –  Oct 30 '21 at 11:20
  • I will update my answer to include how to detect key presses and do all that stuff –  Oct 30 '21 at 11:22
0

The only way it would work in the terminal from what I know is to wait for user input, and they then enter the row, column and number into the terminal. Here is an example:

row = input("Enter a row: ")
col = input("Enter a column: ")
num = input("Enter a number to insert into the grid: ")

And then you would use the values entered to draw the updated grid which you would print to the terminal again, and then await user input again.

Daniel
  • 275
  • 1
  • 9
  • how does one make a grid in a text file ? – confusedstudent Oct 30 '21 at 11:32
  • @confusedstudent Well you would have to use the row and column to edit `board` to have the entered `num` value at the specified row and column, and then just call your `save` function as normal to save it in a text file. – Daniel Oct 30 '21 at 11:38
  • @confusedstudent And by grid I just mean the `board` variable you have in your code that stores the rows and columns of numbers. – Daniel Oct 30 '21 at 11:41
0

If you're OK with making it a text based game, you can loop until the sudoku is complete and valid. Print the current board state and ask for a coordinate assignment.

Make sure that the initial numbers cannot be overridden and allow erasing misplaced numbers (e.g. by assigning them a zero)

Here is a nice printing function for the sudoku board that highlights the initial numbers by placing them between parentheses:

def niceSudo(board):
    side    = len(board)
    base    = int(side**0.5)
    def expandLine(line):
        return line[0]+line[5:9].join([line[1:5]*(base-1)]*base)+line[9:]
    line0  = "  "+expandLine("╔═══╤═══╦═══╗   ")
    line1  = "# "+expandLine("║ . │ . ║ . ║ # ")
    line2  = "  "+expandLine("╟───┼───╫───╢   ")
    line3  = "  "+expandLine("╠═══╪═══╬═══╣   ")
    line4  = "  "+expandLine("╚═══╧═══╩═══╝   ")

    symbol = " 123456789" if base <= 3 else " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
    nums   = [ [""]+[f"({symbol[-n]})" if n<0 else f" {symbol[n]} "  for n in row]
               for row in board ]
    coord  = "   "+"".join(f" {s}  " for s in symbol[1:side+1])+"   "
    lines  = []
    lines.append(coord)
    lines.append(line0)
    for r in range(1,side+1):
        line1n = line1.replace("#",str(symbol[r]))
        lines.append( "".join(n+s for n,s in zip(nums[r-1],line1n.split(" . "))) )
        lines.append([line2,line3,line4][(r%side==0)+(r%base==0)])
    lines.append(coord)
    return lines
        
def printSudoku(*boards):
    print(*(" ".join(ss) for ss in zip(*(niceSudo(b) for b in boards))),sep="\n") 

You will also need a function to check if the board is complete and valid:

def sudokuDone(board):
    side    = len(board)
    base    = int(len(board)**0.5)
    if any( 0 in row for row in board) : return False
    filled = set(range(1,10))
    board = [ [abs(n) for n in row] for row in board]
    if any(set(row) != filled for row in board): return False
    if any(set(col) != filled for col in zip(*board)): return False
    if any(set(v for row in board[r:r+base] for v in row[c:c+base]) != filled
           for r in range(0,side,base) for c in range(0,side,base)):
        return False
    return True

The whole game would be a single loop that prints, asks for coordinate assignments and checks for completion:

def playSudoku(board):
    board = [ [-n for n in row] for row in board ]
    while not sudokuDone(board):
        printSudoku(board)
        command = input("Enter Row,Column=Number: ")
        try:
            r,c,n = map(int,command.replace("=",",").split(","))
        except:
            print("Invalid input")
            continue
        if n not in range(0,10): print("Number must be 0...9");continue
        if r not in range(1,10): print("Row must be 1...9");continue
        if c not in range(1,10): print("col must be 1...9");continue
        if board[r-1][c-1]<0: print("Cannot change initial numbers");continue
        board[r-1][c-1] = n
    printSudoku(board)
    print("Success!!")

Note that, although the printing and validation functions can handle sudokus up to 36x36, I only implemented the 9x9 in this playSudoku function

Test run:

test =  [ [8,0,0, 0,0,0, 0,0,0],
          [0,0,3, 6,0,0, 0,0,0],
          [0,7,0, 0,9,0, 2,0,0],
 
          [0,5,0, 0,0,7, 0,0,0],
          [0,0,0, 0,4,5, 6,0,0],
          [0,0,0, 1,0,0, 0,3,0],

          [0,0,1, 0,0,0, 0,6,8],
          [0,0,8, 5,0,0, 0,1,0],
          [0,9,0, 0,0,0, 4,0,0]
        ]

playSudoku(test)

...

    1   2   3   4   5   6   7   8   9  
  ╔═══╤═══╤═══╦═══╤═══╤═══╦═══╤═══╤═══╗
1 ║(8)│   │   ║   │   │   ║   │   │   ║ 1
  ╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
2 ║   │   │(3)║(6)│   │   ║   │   │   ║ 2
  ╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
3 ║   │(7)│   ║   │(9)│   ║(2)│   │   ║ 3
  ╠═══╪═══╪═══╬═══╪═══╪═══╬═══╪═══╪═══╣
4 ║   │(5)│   ║   │   │(7)║   │   │   ║ 4
  ╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
5 ║   │   │   ║   │(4)│(5)║(6)│   │   ║ 5
  ╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
6 ║   │   │   ║(1)│   │   ║   │(3)│   ║ 6
  ╠═══╪═══╪═══╬═══╪═══╪═══╬═══╪═══╪═══╣
7 ║   │   │(1)║   │   │   ║   │(6)│(8)║ 7
  ╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
8 ║   │   │(8)║(5)│   │   ║   │(1)│   ║ 8
  ╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
9 ║   │(9)│   ║   │   │   ║(4)│   │   ║ 9
  ╚═══╧═══╧═══╩═══╧═══╧═══╩═══╧═══╧═══╝
    1   2   3   4   5   6   7   8   9  
Enter Row,Column=Number: 5,4=2
    1   2   3   4   5   6   7   8   9  
  ╔═══╤═══╤═══╦═══╤═══╤═══╦═══╤═══╤═══╗
1 ║(8)│   │   ║   │   │   ║   │   │   ║ 1
  ╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
2 ║   │   │(3)║(6)│   │   ║   │   │   ║ 2
  ╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
3 ║   │(7)│   ║   │(9)│   ║(2)│   │   ║ 3
  ╠═══╪═══╪═══╬═══╪═══╪═══╬═══╪═══╪═══╣
4 ║   │(5)│   ║   │   │(7)║   │   │   ║ 4
  ╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
5 ║   │   │   ║ 2 │(4)│(5)║(6)│   │   ║ 5
  ╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
6 ║   │   │   ║(1)│   │   ║   │(3)│   ║ 6
  ╠═══╪═══╪═══╬═══╪═══╪═══╬═══╪═══╪═══╣
7 ║   │   │(1)║   │   │   ║   │(6)│(8)║ 7
  ╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
8 ║   │   │(8)║(5)│   │   ║   │(1)│   ║ 8
  ╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
9 ║   │(9)│   ║   │   │   ║(4)│   │   ║ 9
  ╚═══╧═══╧═══╩═══╧═══╧═══╩═══╧═══╧═══╝
    1   2   3   4   5   6   7   8   9  
Enter Row,Column=Number:1,2=1

...

    1   2   3   4   5   6   7   8   9  
  ╔═══╤═══╤═══╦═══╤═══╤═══╦═══╤═══╤═══╗
1 ║(8)│ 1 │ 2 ║ 7 │ 5 │ 4 ║ 3 │ 9 │ 6 ║ 1
  ╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
2 ║ 9 │ 4 │(3)║(6)│ 8 │ 2 ║ 1 │ 5 │ 7 ║ 2
  ╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
3 ║ 6 │(7)│ 5 ║ 3 │(9)│ 1 ║(2)│ 8 │ 4 ║ 3
  ╠═══╪═══╪═══╬═══╪═══╪═══╬═══╪═══╪═══╣
4 ║ 1 │(5)│ 6 ║ 9 │ 3 │(7)║ 8 │ 4 │ 2 ║ 4
  ╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
5 ║ 3 │ 8 │ 9 ║ 2 │(4)│(5)║(6)│ 7 │ 1 ║ 5
  ╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
6 ║ 7 │ 2 │ 4 ║(1)│ 6 │ 8 ║ 9 │(3)│ 5 ║ 6
  ╠═══╪═══╪═══╬═══╪═══╪═══╬═══╪═══╪═══╣
7 ║ 2 │ 3 │(1)║ 4 │ 7 │ 9 ║ 5 │(6)│(8)║ 7
  ╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
8 ║ 4 │ 6 │(8)║(5)│ 2 │ 3 ║ 7 │(1)│ 9 ║ 8
  ╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
9 ║ 5 │(9)│ 7 ║ 8 │ 1 │ 6 ║(4)│ 2 │   ║ 9
  ╚═══╧═══╧═══╩═══╧═══╧═══╩═══╧═══╧═══╝
    1   2   3   4   5   6   7   8   9  
Enter Row,Column=Number: 9,9=3
    1   2   3   4   5   6   7   8   9  
  ╔═══╤═══╤═══╦═══╤═══╤═══╦═══╤═══╤═══╗
1 ║(8)│ 1 │ 2 ║ 7 │ 5 │ 4 ║ 3 │ 9 │ 6 ║ 1
  ╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
2 ║ 9 │ 4 │(3)║(6)│ 8 │ 2 ║ 1 │ 5 │ 7 ║ 2
  ╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
3 ║ 6 │(7)│ 5 ║ 3 │(9)│ 1 ║(2)│ 8 │ 4 ║ 3
  ╠═══╪═══╪═══╬═══╪═══╪═══╬═══╪═══╪═══╣
4 ║ 1 │(5)│ 6 ║ 9 │ 3 │(7)║ 8 │ 4 │ 2 ║ 4
  ╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
5 ║ 3 │ 8 │ 9 ║ 2 │(4)│(5)║(6)│ 7 │ 1 ║ 5
  ╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
6 ║ 7 │ 2 │ 4 ║(1)│ 6 │ 8 ║ 9 │(3)│ 5 ║ 6
  ╠═══╪═══╪═══╬═══╪═══╪═══╬═══╪═══╪═══╣
7 ║ 2 │ 3 │(1)║ 4 │ 7 │ 9 ║ 5 │(6)│(8)║ 7
  ╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
8 ║ 4 │ 6 │(8)║(5)│ 2 │ 3 ║ 7 │(1)│ 9 ║ 8
  ╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
9 ║ 5 │(9)│ 7 ║ 8 │ 1 │ 6 ║(4)│ 2 │ 3 ║ 9
  ╚═══╧═══╧═══╩═══╧═══╧═══╩═══╧═══╧═══╝
    1   2   3   4   5   6   7   8   9  
Success!!
Alain T.
  • 40,517
  • 4
  • 31
  • 51