python使用数独技巧解数独-自动读题填写和下一关

 微信小程序:数独游戏九宫格

#算法1.py
import numpy as np
import copy
from itertools import combinations
class point:
	def __init__(self,行,列):
		self.行=行
		self.列=列
		self.宫=行//3*3+列//3
		self.中的候选数=[*range(1,10)]
class 数独:
	def __init__(self,sudoku):
		self.sudoku=sudoku
		self.待填单元格=initPoint(sudoku)
		self.已填单元格=[]
		self.存在有效方法=True
class 无候选数错误(Exception):
	def __init__(self, msg=''):
		self.message = msg
	def __str__(self):
		return self.message
def 该行数字(行,sudoku):temp=set(sudoku[行]);temp.remove(0);return(list(temp))
def 该列数字(列,sudoku):temp=set(sudoku[:,列]);temp.remove(0);return(list(temp))
def 该宫数字(行,列,sudoku):temp=set(sudoku[行-行%3:行-行%3+3,列-列%3:列-列%3+3].flatten());temp.remove(0);return(list(temp))
def initPoint(sudoku):
	待填单元格=[]
	i=j=0
	while i!=9:
		if sudoku[i][j]==0:
			单元格=point(i,j)
			# print([*该行数字(单元格.行,sudoku),*该列数字(单元格.列,sudoku),*该宫数字(单元格.行,单元格.列,sudoku)])
			for 格中不允许填的数字 in [*该行数字(单元格.行,sudoku),*该列数字(单元格.列,sudoku),*该宫数字(单元格.行,单元格.列,sudoku)]:
				# print(单元格.中的候选数,格中不允许填的数字)
				if 格中不允许填的数字 in 单元格.中的候选数:
					单元格.中的候选数.remove(格中不允许填的数字)
			待填单元格+=[单元格]
		if j==8:i+=1
		j=(j+1 if j!=8 else 0)
	return 待填单元格
def 该行待填单元格(行,数独里的待填单元格):return([i for i in 数独里的待填单元格 if i.行==行 and hasattr(i,'中的候选数')])
def 该列待填单元格(列,数独里的待填单元格):return([i for i in 数独里的待填单元格 if i.列==列 and hasattr(i,'中的候选数')])
def 该宫待填单元格(宫,数独里的待填单元格):return([i for i in 数独里的待填单元格 if i.宫==宫 and hasattr(i,'中的候选数')])
def 这里面的候选数(待填单元格):return([i for p in 待填单元格 for i in p.中的候选数])
def 消除相关候选数(已填单元格,sudoku):
	for 单元格 in 该行待填单元格(已填单元格.行,sudoku.待填单元格)+该列待填单元格(已填单元格.列,sudoku.待填单元格)+该宫待填单元格(已填单元格.宫,sudoku.待填单元格):
		if 已填单元格.value in 单元格.中的候选数:单元格.中的候选数.remove(已填单元格.value)
def 填写(sudoku,单元格,值):
	起到效果(sudoku)
	del 单元格.中的候选数
	单元格.value=sudoku.sudoku[单元格.行][单元格.列]=值
	消除相关候选数(单元格,sudoku)
	sudoku.已填单元格.append(单元格)
	sudoku.待填单元格.remove(单元格)
def 唯一候选数法(sudoku):
	for 单元格 in sudoku.待填单元格[:]:#[:]防止for remove bug
		if len(单元格.中的候选数)==0:raise 无候选数错误('{}行{}列中无候选数'.format(单元格.行+1,单元格.列+1))
		if hasattr(单元格,'中的候选数') and len(单元格.中的候选数)==1:填写(sudoku,单元格,单元格.中的候选数[0])
def 隐性唯一候选数法(sudoku):
	for 单元格 in sudoku.待填单元格[:]:#[:]防止for remove bug
		# if len(单元格.中的候选数)==0:raise 无候选数错误('{}{}格中无候选数'.format(单元格.行,单元格.列))
		for 候选数 in 单元格.中的候选数:
			if 1 in (这里面的候选数(该行待填单元格(单元格.行,sudoku.待填单元格)).count(候选数),这里面的候选数(该列待填单元格(单元格.列,sudoku.待填单元格)).count(候选数),这里面的候选数(该宫待填单元格(单元格.宫,sudoku.待填单元格)).count(候选数)):
				填写(sudoku,单元格,候选数)
				break
def 显式数集删减法(sudoku):
	def 数集删减(待填单元格,plist,set):
		for 单元格 in [i for i in 待填单元格 if i not in plist]:
			temp=copy.deepcopy(单元格.中的候选数)
			# if temp==0:raise 无候选数错误('{}{}格中无候选数'.format(单元格.行,单元格.列))
			单元格.中的候选数=[i for i in 单元格.中的候选数 if i not in set]
			if temp!=单元格.中的候选数:起到效果(sudoku)
	def 显式数集(待填单元格):
		for 数集数 in range(2,6):
			可能的格子=[单元格 for 单元格 in 待填单元格 if len(单元格.中的候选数)<=数集数]
			avail=这里面的候选数(可能的格子)
			if len(可能的格子)<数集数:pass
			elif len(可能的格子)==数集数 and len(set(avail))==数集数:数集删减(待填单元格,可能的格子,set(avail))
			elif len(可能的格子)>数集数:
				for c in combinations(可能的格子,数集数):
					smallset=set([i for 单元格 in c for i in 单元格.中的候选数])
					if len(smallset)==数集数:数集删减(待填单元格,c,smallset)
	for i in range(9):
		显式数集(该行待填单元格(i,sudoku.待填单元格))
		显式数集(该列待填单元格(i,sudoku.待填单元格))
		显式数集(该宫待填单元格(i,sudoku.待填单元格))
def 候选数区块删减法(sudoku):
	def 直宫剪切(sudoku,某个候选数字,aplist,bplist):
		a中有该数字的单元格=[单元格 for 单元格 in aplist if 某个候选数字 in 单元格.中的候选数]
		temp=[单元格 in bplist for 单元格 in a中有该数字的单元格]
		if all(temp) and temp:#a中所有有该数字的单元格都在b中,all()对空列表会返回Ture
			for b的单元格 in bplist:
				if b的单元格 not in a中有该数字的单元格 and 某个候选数字 in b的单元格.中的候选数:
					b的单元格.中的候选数.remove(某个候选数字)
					起到效果(sudoku)

	def 该宫的行列(宫):return(zip(*[(i+宫//3*3,i+宫%3*3) for i in [0,1,2]]))
	宫=0;某个候选数字=1
	while 宫!=9:
		宫行,宫列=该宫的行列(宫)
		for 行 in 宫行:
			直宫剪切(sudoku,某个候选数字,该行待填单元格(行,sudoku.待填单元格),该宫待填单元格(宫,sudoku.待填单元格))
			直宫剪切(sudoku,某个候选数字,该宫待填单元格(宫,sudoku.待填单元格),该行待填单元格(行,sudoku.待填单元格))
		for 列 in 宫列:
			直宫剪切(sudoku,某个候选数字,该列待填单元格(列,sudoku.待填单元格),该宫待填单元格(宫,sudoku.待填单元格))
			直宫剪切(sudoku,某个候选数字,该宫待填单元格(宫,sudoku.待填单元格),该列待填单元格(列,sudoku.待填单元格))
		if 某个候选数字==9:宫+=1
		某个候选数字=(某个候选数字+1 if 某个候选数字!=9 else 1)
def 隐性数集删减法(sudoku):
	def 数集删减(plist,set):
		for 单元格 in plist:单元格.中的候选数=[i for i in 单元格.中的候选数 if i in set]
	def 隐式数集(待填单元格):
		for 数集数 in range(2,5):
			for c in combinations(range(1,10),数集数):
				可能的格子=[单元格 for 单元格 in 待填单元格 if any(ci in 单元格.中的候选数 for ci in c)]
				if len(可能的格子)==数集数 and all(ci in set(这里面的候选数(可能的格子)) for ci in c):数集删减(可能的格子,c)
	for i in range(9):
		隐式数集(该行待填单元格(i,sudoku.待填单元格))
		隐式数集(该列待填单元格(i,sudoku.待填单元格))
		隐式数集(该宫待填单元格(i,sudoku.待填单元格))
def 候选数矩形删减法(sudoku):
	def 数集删减行(行,列,数,sudoku):#是这两行但不是这两列的格子删掉数
		# # print(行,列)
		for i in [单元格 for 单元格 in sudoku.待填单元格 if 单元格.行 in 行 and 单元格.列 not in 列]:
			try:
				i.中的候选数.remove(数)
				起到效果(sudoku)
			except(ValueError):pass
	def 数集删减列(列,行,数,sudoku):#是这两列但不是这两行的格子删掉数
		for i in [单元格 for 单元格 in sudoku.待填单元格 if 单元格.列 in 列 and 单元格.行 not in 行]:
			try:
				i.中的候选数.remove(数)
				起到效果(sudoku)
			except(ValueError):pass
	def 矩形数集(alist,blist,数,行列='行'):#给定两列,如果都有两个该候选数且在两行中,删除行中其他数
		alist=[单元格 for 单元格 in alist if 数 in 单元格.中的候选数]#列中含有候选数的单元格
		blist=[单元格 for 单元格 in blist if 数 in 单元格.中的候选数]
		#if列中含有候选数的单元格只有两个,且他们都集中在两行内
		if not (alist or blist):return()
		if 行列=='行':
			要删减的列=set([单元格.列 for 单元格 in alist]+[单元格.列 for 单元格 in blist])
			if len(alist)==len(blist)==len(要删减的列)==2:数集删减列(要删减的列,[alist[0].行,blist[0].行],数,sudoku)
		else:
			要删减的行=set([单元格.行 for 单元格 in alist]+[单元格.行 for 单元格 in blist])
			if len(alist)==len(blist)==len(要删减的行)==2:数集删减行(要删减的行,[alist[0].列,blist[0].列],数,sudoku)
	i=1;j=0
	while j!=36:
		a,b=[c for c in combinations(range(9),2)][j]
		矩形数集(该行待填单元格(a,sudoku.待填单元格),该行待填单元格(b,sudoku.待填单元格),i)
		矩形数集(该列待填单元格(a,sudoku.待填单元格),该列待填单元格(b,sudoku.待填单元格),i,'列')
		if i==9:j+=1
		i=(i+1 if i!=9 else 1)
迭代次数=0
def 暴力破解(sudoku):
	# # print('爆破')
	global 迭代次数
	迭代次数+=1
	# print(迭代次数)
	while sudoku.待填单元格:
		
		数独副本=copy.deepcopy(sudoku)
		最小单元格候选数数量=9
		for 单元格 in sudoku.待填单元格:
			if len(单元格.中的候选数)==2:
				尝试的单元格=单元格
				break
			elif len(单元格.中的候选数)<最小单元格候选数数量:
				最小单元格候选数数量=len(单元格.中的候选数)
				尝试的单元格=单元格
		尝试的单元格坐标存档=copy.deepcopy([尝试的单元格.行,尝试的单元格.列])
		if not 尝试的单元格.中的候选数:raise 无候选数错误
		# print('尝试的数',尝试的单元格坐标存档,尝试的单元格.中的候选数[-1],'\n',sudoku.sudoku)
		尝试的单元格.中的候选数=[尝试的单元格.中的候选数[-1]]
		try:
			# print('计算')
			sudoku=计算(sudoku)
		except 无候选数错误:
			# print('无候选数错误')
			# print('尝试的数',尝试的单元格坐标存档,'\n',sudoku.sudoku)
			# # print(sudoku.sudoku)
			sudoku=数独副本
			# # print(sudoku.sudoku)
			# # print('?')
			for 单元格 in sudoku.待填单元格:
				# print('for')
				if [单元格.行,单元格.列]==尝试的单元格坐标存档:
					# print('if')
					# print(单元格.中的候选数)
					del 单元格.中的候选数[-1]
					if len(单元格.中的候选数)==1:填写(sudoku,单元格,单元格.中的候选数[0])
					# try:# print(单元格.中的候选数)
					# except AttributeError:# print(单元格.value)
			# # print(sudoku.待填单元格[0].中的候选数)
		else:
			# print('else')
			# print('尝试的数',尝试的单元格坐标存档,'\n',sudoku.sudoku)
			# print(sudoku)
			for 单元格 in sudoku.待填单元格:
				# print('else for')
				# print([单元格.行,单元格.列])
				if [单元格.行,单元格.列]==尝试的单元格坐标存档:
					# print('else for if')
					填写(sudoku,单元格,单元格.中的候选数[-1])
				# print('else for end')
			# print('else end')
		finally:
			# print('finally')
			del 数独副本
			del 尝试的单元格坐标存档
			# print('迭代次数',迭代次数)
	迭代次数-=1
	# print(sudoku.sudoku)
	return(sudoku)
def 起到效果(sudoku):
	sudoku.有效=True
	sudoku.存在有效方法=True
		
def 计算(sudoku):
	if type(sudoku)!=数独:sudoku=数独(np.array(sudoku).reshape(9,9))
	解题技巧=[候选数矩形删减法,隐性数集删减法 ,候选数区块删减法,显式数集删减法 ,隐性唯一候选数法,唯一候选数法]
	# 解题技巧=[显式数集删减法 ,隐性唯一候选数法,唯一候选数法]
	while sudoku.存在有效方法:
		sudoku.存在有效方法=False
		for func in 解题技巧:
			sudoku.有效=True
			while sudoku.有效:#该方法有效就继续计算至无效
				sudoku.有效=False
				# # print('前',[p.中的候选数 for p in sudoku.待填单元格])
				# # print(这里面的候选数(sudoku.待填单元格))
				func(sudoku)#尝试更改有效和存在有效为True
				# # print(func)
				# # print(这里面的候选数(sudoku.待填单元格))
	# # print('已',[p.value for p in sudoku.已填单元格])
	# # print('未',[p.中的候选数 for p in sudoku.待填单元格])
	if sudoku.待填单元格:#如果还有未解出的
		sudoku.存在有效方法=True
		# print('爆破')
		sudoku=暴力破解(sudoku)
		# print('爆破end')
	# for i in range(9):# print('未',[(单元格.中的候选数) for 单元格 in sudoku.待填单元格 if 单元格.行==i and 单元格.宫!='a'])#查看某格的候选数
	return sudoku
test唯一=[4, 3, 9, 0, 6, 0, 2, 8, 1, 6, 0, 0, 0, 4, 2, 7, 5, 3, 2, 5, 7, 0, 1, 8, 0, 9, 6, 5, 0, 0, 0, 8, 0, 0, 6, 9, 0, 8, 0, 1, 0, 4, 5, 0, 7, 9, 0, 1, 0, 2, 5, 0, 3, 4, 1, 6, 0, 4, 0, 9, 3, 0, 8, 7, 0, 0, 0, 3, 0, 6, 0, 2, 8, 4, 3, 2, 7, 6, 0, 1, 5]
test隐唯=[4, 0, 3, 0, 0, 1, 0, 2, 0, 0, 2, 6, 0, 7, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 8, 0, 6, 0, 3, 0, 3, 6, 0, 0, 0, 9, 2, 0, 8, 0, 0, 0, 2, 0, 0, 6, 9, 4, 7, 0, 0, 3, 0, 0, 4, 8, 0, 0, 5, 0, 0, 8, 0, 3, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0]
test显式=[0, 0, 9, 0, 8, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 3, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 7, 0, 0, 0, 0, 0, 7, 0, 0, 5, 0, 2, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 5, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 6, 0]
test区块=[0, 0, 4, 6, 0, 2, 0, 0, 0, 6, 0, 0, 0, 3, 0, 0, 0, 4, 0, 2, 0, 4, 0, 0, 0, 9, 0, 9, 8, 0, 0, 4, 0, 3, 5, 0, 1, 0, 3, 0, 0, 0, 0, 4, 0, 4, 6, 0, 0, 0, 3, 8, 0, 7, 0, 3, 6, 0, 2, 4, 0, 7, 0, 0, 4, 0, 0, 6, 1, 0, 3, 5, 0, 1, 9, 3, 0, 0, 4, 6, 0]
test隐式=[5, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 7, 0, 0, 0, 0, 0, 4, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 4, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 1, 0, 0, 7, 0, 2, 0, 6, 0, 0, 0, 0, 1, 0, 0, 0, 0, 8, 0, 0, 0, 0, 4, 5, 0, 0, 0, 0]
test矩形=[0, 0, 0, 3, 0, 0, 1, 0, 0, 5, 0, 0, 4, 0, 1, 0, 9, 0, 0, 0, 1, 0, 2, 8, 6, 0, 0, 0, 9, 0, 8, 0, 0, 0, 0, 1, 0, 0, 8, 0, 1, 7, 0, 0, 2, 0, 1, 0, 0, 4, 0, 8, 0, 0, 0, 0, 4, 0, 8, 5, 0, 0, 0, 3, 0, 0, 1, 0, 0, 0, 4, 0, 0, 0, 2, 6, 3, 4, 0, 0, 0]
test爆破=[0, 2, 6, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 9, 0, 2, 0, 0, 3, 0, 0, 0, 8, 0, 6, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 6, 4, 0, 0, 0, 0, 0, 0, 0, 3, 0, 9, 3, 4, 0, 6, 1, 2, 0, 0, 0, 1, 8, 7, 0, 0, 0, 0, 0, 0, 9, 0, 1, 0, 0, 0, 5, 0, 4, 0, 0, 0, 0, 9, 1, 0]
sudoku=test爆破
# print(计算(sudoku).sudoku)
#主程序
from win32gui import *
from PIL import ImageGrab,Image, ImageEnhance
from ctypes import windll
from win32con import SW_RESTORE
import cv2
import numpy as np
import os
from time import sleep
import pyautogui
def PIL_to_cv2(img):return(cv2.cvtColor(np.array(img),cv2.COLOR_RGB2BGR))

def 窗口置顶(窗口):
	if IsIconic(窗口):ShowWindow(窗口, SW_RESTORE)
	else:SetForegroundWindow(窗口)
	sleep(0.3)
def 题目图片(窗口):
	窗口坐标=GetWindowRect(窗口)
	# ImageGrab.grab(窗口坐标).show()
	return(ImageGrab.grab([窗口坐标[i]+(20,121,-20,-322)[i] for i in range(4)]))
def 图片识别(图片):
	def 识别数字(nppic):
		res=[cv2.matchTemplate(nppic,template,cv2.TM_CCOEFF_NORMED).max() for template in [cv2.imread("digital/{}".format(x)) for x in os.listdir("digital")]]
		if max(res)>=0.65:return(res.index(max(res))+1)
		else:return 0
	图片=PIL_to_cv2(图片)
	upleft=[];lowright=[]
	#计算图片角坐标
	# for i in range(len(图片)):
		# for j in range(len(图片[i])):
			# if   all(c==1 or np.var([sum(图片[(i+d)%len(图片)][j]) for d in range(40)]+[sum(图片[i][(j+e)%len(图片[i])]) for e in range(40)])==0 if (str(图片[a][b]) in ('[255 255 255]','[225 247 255]'))==c else 0 for a,b,c in [[i,j,1],[i-1,j,0],[i,j-1,0]]):  upleft+=[(j,i)]
			# elif all(c==1 or np.var([sum(图片[i-d][j]) for d in range(40)]+[sum(图片[i][j-e]) for e in range(40)])==0 if (str(图片[a][b]) in ('[255 255 255]','[225 247 255]'))==c  else 0 for a,b,c in [[i,j,1],[i+1,j,0],[i,j+1,0]]):lowright+=[(j,i)]
		# print(i)
	# print(*zip(upleft,lowright),'len=',len(upleft),sep=',')
	w=((2,43),(46,89),(92,133),(139,180),(184,225),(229,270),(276,317),(321,363),(367,407))
	h=((3,44),(47,90),(94,134),(140,181),(185,227),(231,272),(279,319),(322,365),(368,409))
	
	# cv2.imshow('t',图片[2:43,3:44])
	# cv2.waitKey()
	# print(识别数字(图片[2:43,3:44]))
	sudoku=[识别数字(图片[a:b,c:d]) for a,b in w for c,d in h]
	# print(np.array(sudoku).reshape(9,9))
	# print(sudoku)
	if len([i for i in sudoku if i!=0])<17:return(False)
	return(sudoku)
	
# print(图片识别(Image.open(r'5.png')))
# print(识别数字(cv2.imread('5.jpg')))
def 填写(sudoku,窗口):
	窗口坐标=GetWindowRect(窗口)
	九宫格坐标=[窗口坐标[i]+(20,121,-20,-322)[i] for i in range(4)]#(左,上,右,下)
	w=[22.5, 67.5, 112.5, 159.5, 204.5, 249.5, 296.5, 342.0, 387.0]#九宫格坐标 
	h=[23.5, 68.5, 114.0, 160.5, 206.0, 251.5, 299.0, 343.5, 388.5]#九宫格
	按钮dict={1:(118,618),2:(192,618),3:(266,618),4:(340,618),5:(414,618),6:(118,667),7:(192,667),8:(266,667),9:(340,667)}#窗口坐标

	鼠标坐标表=[[单元格.value,(w[单元格.列]+九宫格坐标[0],h[单元格.行]+九宫格坐标[1]),(按钮dict[单元格.value][0]+窗口坐标[0],按钮dict[单元格.value][1]+窗口坐标[1])] for 单元格 in sudoku.已填单元格]
	# print(鼠标坐标表)
	# print(1)
	new鼠标坐标表=[]
	# while 鼠标坐标表:
		# print(2)
		# for i in range(1,10):
			# if not 鼠标坐标表:break
			# if 鼠标坐标表[0][0]==i:
				# print(i)
				# print('格',鼠标坐标表[0][1])
				# print('按钮',鼠标坐标表[0][2])

				# del 鼠标坐标表[0]

	while 鼠标坐标表:
		for i in range(1,10):
			for j in 鼠标坐标表[:]:
				if j[0]==i:
					new鼠标坐标表+=[j]
					鼠标坐标表.remove(j)
					break
		# new鼠标坐标表+=["sleep"]
	# sleeptime=0
	
	for i in new鼠标坐标表:
		# sleeptime+=0.03
		# if i=='sleep':
			# sleep(sleeptime)
			# continue
		pyautogui.click(i[1])
		pyautogui.click(i[2])
	pyautogui.click(new鼠标坐标表[-1][2])#老是最后一个点不上不知道为什么
	
# sudoku=1
# 游戏窗口=FindWindow(0, "数独游戏九宫格")
# 填写(sudoku,游戏窗口)
from 算法1 import 计算
windll.user32.SetProcessDPIAware()#系统放缩还原
游戏窗口=FindWindow(0, "数独游戏九宫格")
# print(sudoku)

for 自动解题次数 in range(1):
	窗口置顶(游戏窗口)
	识按钮图=cv2.minMaxLoc(cv2.matchTemplate(cv2.cvtColor(np.asarray(pyautogui.screenshot(region=None)),cv2.COLOR_RGB2BGR),cv2.imread('next.png'),cv2.TM_CCOEFF_NORMED))
	if 识按钮图[1]>0.65:pyautogui.click(识按钮图[-1])
	try:填写(计算(图片识别(题目图片(游戏窗口))),游戏窗口)
	except:pass
	# print(a)
	# print(sudoku.sudoku)
	# 窗口置顶(游戏窗口)
	sleep(0.9)

使用的文件:

 

 

 几个坐标表是我另写程序测的像素

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值